@servicetitan/launchdarkly-service 33.1.0 → 34.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.
@@ -1 +1 @@
1
- {"version":3,"file":"feature-flag-provider.d.ts","sourceRoot":"","sources":["../src/feature-flag-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAuB,MAAM,OAAO,CAAC;AAI/D,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE,iBAAiB,6BAclE"}
1
+ {"version":3,"file":"feature-flag-provider.d.ts","sourceRoot":"","sources":["../src/feature-flag-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAuB,MAAM,OAAO,CAAC;AAG/D,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE,iBAAiB,6BAclE"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/feature-flag-provider.tsx"],"sourcesContent":["import { useDependencies } from '@servicetitan/react-ioc';\nimport { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';\nimport { PropsWithChildren, useEffect, useState } from 'react';\n\nimport { FeatureFlagStore } from './feature-flag-store';\n\nexport function FeatureFlagProvider({ children }: PropsWithChildren) {\n const [initialized, setInitialized] = useState(false);\n const [{ setFlags }] = useDependencies(FeatureFlagStore);\n const client = useLDClient();\n const flags = useFlags();\n\n useEffect(() => {\n if (client) {\n setFlags(flags);\n setInitialized(true);\n }\n }, [client, flags, setFlags]);\n\n return initialized ? children : null;\n}\n"],"names":["useDependencies","useFlags","useLDClient","useEffect","useState","FeatureFlagStore","FeatureFlagProvider","children","initialized","setInitialized","setFlags","client","flags"],"mappings":"AAAA,SAASA,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,QAAQ,EAAEC,WAAW,QAAQ,gCAAgC;AACtE,SAA4BC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAE/D,SAASC,gBAAgB,QAAQ,uBAAuB;AAExD,OAAO,SAASC,oBAAoB,EAAEC,QAAQ,EAAqB;IAC/D,MAAM,CAACC,aAAaC,eAAe,GAAGL,SAAS;IAC/C,MAAM,CAAC,EAAEM,QAAQ,EAAE,CAAC,GAAGV,gBAAgBK;IACvC,MAAMM,SAAST;IACf,MAAMU,QAAQX;IAEdE,UAAU;QACN,IAAIQ,QAAQ;YACRD,SAASE;YACTH,eAAe;QACnB;IACJ,GAAG;QAACE;QAAQC;QAAOF;KAAS;IAE5B,OAAOF,cAAcD,WAAW;AACpC"}
1
+ {"version":3,"sources":["../src/feature-flag-provider.tsx"],"sourcesContent":["import { useDependencies } from '@servicetitan/react-ioc';\nimport { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';\nimport { PropsWithChildren, useEffect, useState } from 'react';\nimport { FeatureFlagStore } from './feature-flag-store';\n\nexport function FeatureFlagProvider({ children }: PropsWithChildren) {\n const [initialized, setInitialized] = useState(false);\n const [{ setFlags }] = useDependencies(FeatureFlagStore);\n const client = useLDClient();\n const flags = useFlags();\n\n useEffect(() => {\n if (client) {\n setFlags(flags);\n setInitialized(true);\n }\n }, [client, flags, setFlags]);\n\n return initialized ? children : null;\n}\n"],"names":["useDependencies","useFlags","useLDClient","useEffect","useState","FeatureFlagStore","FeatureFlagProvider","children","initialized","setInitialized","setFlags","client","flags"],"mappings":"AAAA,SAASA,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,QAAQ,EAAEC,WAAW,QAAQ,gCAAgC;AACtE,SAA4BC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAC/D,SAASC,gBAAgB,QAAQ,uBAAuB;AAExD,OAAO,SAASC,oBAAoB,EAAEC,QAAQ,EAAqB;IAC/D,MAAM,CAACC,aAAaC,eAAe,GAAGL,SAAS;IAC/C,MAAM,CAAC,EAAEM,QAAQ,EAAE,CAAC,GAAGV,gBAAgBK;IACvC,MAAMM,SAAST;IACf,MAAMU,QAAQX;IAEdE,UAAU;QACN,IAAIQ,QAAQ;YACRD,SAASE;YACTH,eAAe;QACnB;IACJ,GAAG;QAACE;QAAQC;QAAOF;KAAS;IAE5B,OAAOF,cAAcD,WAAW;AACpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ld-provider.d.ts","sourceRoot":"","sources":["../src/ld-provider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEH,cAAc,IAAI,kBAAkB,EACvC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAmC,MAAM,OAAO,CAAC;AAO/E,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,SAAS,CAAC,GAAG;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAC,cAAc,CAAC,CA+C3D,CAAC"}
1
+ {"version":3,"file":"ld-provider.d.ts","sourceRoot":"","sources":["../src/ld-provider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEH,cAAc,IAAI,kBAAkB,EACvC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAmC,MAAM,OAAO,CAAC;AAM/E,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,SAAS,CAAC,GAAG;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAkD3D,CAAC"}
@@ -18,12 +18,16 @@ export const LDProvider = provide({
18
18
  const [counter, forceUpdate] = useReducer((x)=>x + 1, 0);
19
19
  useEffect(()=>{
20
20
  (async function initializeClient() {
21
+ var _ref;
22
+ const options = (ldService === null || ldService === void 0 ? void 0 : ldService.application) ? {
23
+ application: ldService.application
24
+ } : undefined;
21
25
  const config = {
22
26
  clientSideID,
23
- context
27
+ context,
28
+ options
24
29
  };
25
- var _ldService_getClient;
26
- const client = (_ldService_getClient = ldService === null || ldService === void 0 ? void 0 : ldService.getClient(config)) !== null && _ldService_getClient !== void 0 ? _ldService_getClient : getLDClient(config);
30
+ const client = (_ref = ldService === null || ldService === void 0 ? void 0 : ldService.getClient(config)) !== null && _ref !== void 0 ? _ref : getLDClient(config);
27
31
  if (waitForInitialization) {
28
32
  try {
29
33
  await client.waitForInitialization(5);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ld-provider.tsx"],"sourcesContent":["import { Log } from '@servicetitan/log-service';\nimport { provide, useOptionalDependencies } from '@servicetitan/react-ioc';\nimport { LDClient } from 'launchdarkly-js-client-sdk';\nimport {\n LDProvider as BaseLDProvider,\n ProviderConfig as BaseProviderConfig,\n} from 'launchdarkly-react-client-sdk';\nimport { FC, PropsWithChildren, useEffect, useReducer, useState } from 'react';\n\nimport { FeatureFlagProvider } from './feature-flag-provider';\nimport { FeatureFlagStore } from './feature-flag-store';\nimport { getLDClient } from './get-ld-client';\nimport { LD_SERVICE_TOKEN } from './types';\n\nexport type ProviderConfig = Pick<BaseProviderConfig, 'clientSideID' | 'context'> & {\n projectName: string;\n waitForInitialization?: boolean;\n};\n\nexport const LDProvider: FC<PropsWithChildren<ProviderConfig>> = provide({\n singletons: [FeatureFlagStore],\n})(props => {\n const { children, clientSideID, context, projectName, waitForInitialization = true } = props;\n const [ldClient, setLDClient] = useState<LDClient>();\n const [ldService, log] = useOptionalDependencies(LD_SERVICE_TOKEN, Log);\n const [counter, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n useEffect(() => {\n (async function initializeClient() {\n const config = { clientSideID, context };\n const client = ldService?.getClient(config) ?? getLDClient(config);\n if (waitForInitialization) {\n try {\n await client.waitForInitialization(5);\n } catch (error) {\n log?.error({\n category: 'LaunchDarkly',\n code: 'InitializationFailed',\n error,\n message: `\"${projectName}\" client failed to initialize`,\n });\n }\n }\n setLDClient(client);\n })();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [clientSideID]); // only reload if clientSideID changes\n\n useEffect(() => {\n if (!waitForInitialization && ldClient) {\n ldClient.on('initialized', forceUpdate);\n return () => {\n ldClient.off('initialized', forceUpdate);\n };\n }\n }, [ldClient, waitForInitialization]);\n\n if (!ldClient) {\n return null;\n }\n\n return (\n <BaseLDProvider key={counter.toString()} clientSideID={clientSideID} ldClient={ldClient}>\n <FeatureFlagProvider>{children}</FeatureFlagProvider>\n </BaseLDProvider>\n );\n});\n"],"names":["Log","provide","useOptionalDependencies","LDProvider","BaseLDProvider","useEffect","useReducer","useState","FeatureFlagProvider","FeatureFlagStore","getLDClient","LD_SERVICE_TOKEN","singletons","props","children","clientSideID","context","projectName","waitForInitialization","ldClient","setLDClient","ldService","log","counter","forceUpdate","x","initializeClient","config","client","getClient","error","category","code","message","on","off","toString"],"mappings":";AAAA,SAASA,GAAG,QAAQ,4BAA4B;AAChD,SAASC,OAAO,EAAEC,uBAAuB,QAAQ,0BAA0B;AAE3E,SACIC,cAAcC,cAAc,QAEzB,gCAAgC;AACvC,SAAgCC,SAAS,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,QAAQ;AAE/E,SAASC,mBAAmB,QAAQ,0BAA0B;AAC9D,SAASC,gBAAgB,QAAQ,uBAAuB;AACxD,SAASC,WAAW,QAAQ,kBAAkB;AAC9C,SAASC,gBAAgB,QAAQ,UAAU;AAO3C,OAAO,MAAMR,aAAoDF,QAAQ;IACrEW,YAAY;QAACH;KAAiB;AAClC,GAAGI,CAAAA;IACC,MAAM,EAAEC,QAAQ,EAAEC,YAAY,EAAEC,OAAO,EAAEC,WAAW,EAAEC,wBAAwB,IAAI,EAAE,GAAGL;IACvF,MAAM,CAACM,UAAUC,YAAY,GAAGb;IAChC,MAAM,CAACc,WAAWC,IAAI,GAAGpB,wBAAwBS,kBAAkBX;IACnE,MAAM,CAACuB,SAASC,YAAY,GAAGlB,WAAW,CAACmB,IAAcA,IAAI,GAAG;IAEhEpB,UAAU;QACL,CAAA,eAAeqB;YACZ,MAAMC,SAAS;gBAAEZ;gBAAcC;YAAQ;gBACxBK;YAAf,MAAMO,SAASP,CAAAA,uBAAAA,sBAAAA,gCAAAA,UAAWQ,SAAS,CAACF,qBAArBN,kCAAAA,uBAAgCX,YAAYiB;YAC3D,IAAIT,uBAAuB;gBACvB,IAAI;oBACA,MAAMU,OAAOV,qBAAqB,CAAC;gBACvC,EAAE,OAAOY,OAAO;oBACZR,gBAAAA,0BAAAA,IAAKQ,KAAK,CAAC;wBACPC,UAAU;wBACVC,MAAM;wBACNF;wBACAG,SAAS,CAAC,CAAC,EAAEhB,YAAY,6BAA6B,CAAC;oBAC3D;gBACJ;YACJ;YACAG,YAAYQ;QAChB,CAAA;IACA,uDAAuD;IAC3D,GAAG;QAACb;KAAa,GAAG,sCAAsC;IAE1DV,UAAU;QACN,IAAI,CAACa,yBAAyBC,UAAU;YACpCA,SAASe,EAAE,CAAC,eAAeV;YAC3B,OAAO;gBACHL,SAASgB,GAAG,CAAC,eAAeX;YAChC;QACJ;IACJ,GAAG;QAACL;QAAUD;KAAsB;IAEpC,IAAI,CAACC,UAAU;QACX,OAAO;IACX;IAEA,qBACI,KAACf;QAAwCW,cAAcA;QAAcI,UAAUA;kBAC3E,cAAA,KAACX;sBAAqBM;;OADLS,QAAQa,QAAQ;AAI7C,GAAG"}
1
+ {"version":3,"sources":["../src/ld-provider.tsx"],"sourcesContent":["import { Log } from '@servicetitan/log-service';\nimport { provide, useOptionalDependencies } from '@servicetitan/react-ioc';\nimport { LDClient } from 'launchdarkly-js-client-sdk';\nimport {\n LDProvider as BaseLDProvider,\n ProviderConfig as BaseProviderConfig,\n} from 'launchdarkly-react-client-sdk';\nimport { FC, PropsWithChildren, useEffect, useReducer, useState } from 'react';\nimport { FeatureFlagProvider } from './feature-flag-provider';\nimport { FeatureFlagStore } from './feature-flag-store';\nimport { getLDClient } from './get-ld-client';\nimport { LD_SERVICE_TOKEN } from './types';\n\nexport type ProviderConfig = Pick<BaseProviderConfig, 'clientSideID' | 'context'> & {\n projectName: string;\n waitForInitialization?: boolean;\n};\n\nexport const LDProvider: FC<PropsWithChildren<ProviderConfig>> = provide({\n singletons: [FeatureFlagStore],\n})(props => {\n const { children, clientSideID, context, projectName, waitForInitialization = true } = props;\n const [ldClient, setLDClient] = useState<LDClient>();\n const [ldService, log] = useOptionalDependencies(LD_SERVICE_TOKEN, Log);\n const [counter, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n useEffect(() => {\n (async function initializeClient() {\n const options = ldService?.application\n ? { application: ldService.application }\n : undefined;\n const config: BaseProviderConfig = { clientSideID, context, options };\n const client = ldService?.getClient(config) ?? getLDClient(config);\n if (waitForInitialization) {\n try {\n await client.waitForInitialization(5);\n } catch (error) {\n log?.error({\n category: 'LaunchDarkly',\n code: 'InitializationFailed',\n error,\n message: `\"${projectName}\" client failed to initialize`,\n });\n }\n }\n setLDClient(client);\n })();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [clientSideID]); // only reload if clientSideID changes\n\n useEffect(() => {\n if (!waitForInitialization && ldClient) {\n ldClient.on('initialized', forceUpdate);\n return () => {\n ldClient.off('initialized', forceUpdate);\n };\n }\n }, [ldClient, waitForInitialization]);\n\n if (!ldClient) {\n return null;\n }\n\n return (\n <BaseLDProvider key={counter.toString()} clientSideID={clientSideID} ldClient={ldClient}>\n <FeatureFlagProvider>{children}</FeatureFlagProvider>\n </BaseLDProvider>\n );\n});\n"],"names":["Log","provide","useOptionalDependencies","LDProvider","BaseLDProvider","useEffect","useReducer","useState","FeatureFlagProvider","FeatureFlagStore","getLDClient","LD_SERVICE_TOKEN","singletons","props","children","clientSideID","context","projectName","waitForInitialization","ldClient","setLDClient","ldService","log","counter","forceUpdate","x","initializeClient","options","application","undefined","config","client","getClient","error","category","code","message","on","off","toString"],"mappings":";AAAA,SAASA,GAAG,QAAQ,4BAA4B;AAChD,SAASC,OAAO,EAAEC,uBAAuB,QAAQ,0BAA0B;AAE3E,SACIC,cAAcC,cAAc,QAEzB,gCAAgC;AACvC,SAAgCC,SAAS,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,QAAQ;AAC/E,SAASC,mBAAmB,QAAQ,0BAA0B;AAC9D,SAASC,gBAAgB,QAAQ,uBAAuB;AACxD,SAASC,WAAW,QAAQ,kBAAkB;AAC9C,SAASC,gBAAgB,QAAQ,UAAU;AAO3C,OAAO,MAAMR,aAAoDF,QAAQ;IACrEW,YAAY;QAACH;KAAiB;AAClC,GAAGI,CAAAA;IACC,MAAM,EAAEC,QAAQ,EAAEC,YAAY,EAAEC,OAAO,EAAEC,WAAW,EAAEC,wBAAwB,IAAI,EAAE,GAAGL;IACvF,MAAM,CAACM,UAAUC,YAAY,GAAGb;IAChC,MAAM,CAACc,WAAWC,IAAI,GAAGpB,wBAAwBS,kBAAkBX;IACnE,MAAM,CAACuB,SAASC,YAAY,GAAGlB,WAAW,CAACmB,IAAcA,IAAI,GAAG;IAEhEpB,UAAU;QACL,CAAA,eAAeqB;;YACZ,MAAMC,UAAUN,CAAAA,sBAAAA,gCAAAA,UAAWO,WAAW,IAChC;gBAAEA,aAAaP,UAAUO,WAAW;YAAC,IACrCC;YACN,MAAMC,SAA6B;gBAAEf;gBAAcC;gBAASW;YAAQ;YACpE,MAAMI,iBAASV,sBAAAA,gCAAAA,UAAWW,SAAS,CAACF,8CAAWpB,YAAYoB;YAC3D,IAAIZ,uBAAuB;gBACvB,IAAI;oBACA,MAAMa,OAAOb,qBAAqB,CAAC;gBACvC,EAAE,OAAOe,OAAO;oBACZX,gBAAAA,0BAAAA,IAAKW,KAAK,CAAC;wBACPC,UAAU;wBACVC,MAAM;wBACNF;wBACAG,SAAS,CAAC,CAAC,EAAEnB,YAAY,6BAA6B,CAAC;oBAC3D;gBACJ;YACJ;YACAG,YAAYW;QAChB,CAAA;IACA,uDAAuD;IAC3D,GAAG;QAAChB;KAAa,GAAG,sCAAsC;IAE1DV,UAAU;QACN,IAAI,CAACa,yBAAyBC,UAAU;YACpCA,SAASkB,EAAE,CAAC,eAAeb;YAC3B,OAAO;gBACHL,SAASmB,GAAG,CAAC,eAAed;YAChC;QACJ;IACJ,GAAG;QAACL;QAAUD;KAAsB;IAEpC,IAAI,CAACC,UAAU;QACX,OAAO;IACX;IAEA,qBACI,KAACf;QAAwCW,cAAcA;QAAcI,UAAUA;kBAC3E,cAAA,KAACX;sBAAqBM;;OADLS,QAAQgB,QAAQ;AAI7C,GAAG"}
@@ -1,2 +1,8 @@
1
- export declare const LDServiceProvider: (({ children }: any) => any) & import("@servicetitan/react-ioc/dist/provide").WrappedComponent<({ children }: any) => any>;
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { LDApplication } from './types';
3
+ interface LDServiceProviderProps {
4
+ application?: LDApplication;
5
+ }
6
+ export declare const LDServiceProvider: FC<PropsWithChildren<LDServiceProviderProps>>;
7
+ export {};
2
8
  //# sourceMappingURL=ld-service-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ld-service-provider.d.ts","sourceRoot":"","sources":["../src/ld-service-provider.tsx"],"names":[],"mappings":"AASA,eAAO,MAAM,iBAAiB,4HAEA,CAAC"}
1
+ {"version":3,"file":"ld-service-provider.d.ts","sourceRoot":"","sources":["../src/ld-service-provider.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAqB,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAoB,aAAa,EAAa,MAAM,SAAS,CAAC;AAMrE,UAAU,sBAAsB;IAC5B,WAAW,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CAkB1E,CAAC"}
@@ -1,4 +1,5 @@
1
- import { provide } from '@servicetitan/react-ioc';
1
+ import { provide, useDependencies } from '@servicetitan/react-ioc';
2
+ import { useEffect, useRef } from 'react';
2
3
  import { getLDClient } from './get-ld-client';
3
4
  import { LD_SERVICE_TOKEN } from './types';
4
5
  const ldService = {
@@ -12,6 +13,21 @@ export const LDServiceProvider = provide({
12
13
  inherit: true
13
14
  }
14
15
  ]
15
- })(({ children })=>children);
16
+ })(({ children, application })=>{
17
+ const [providedLDService] = useDependencies(LD_SERVICE_TOKEN);
18
+ const prevApplication = useRef(providedLDService.application);
19
+ if (providedLDService === ldService || !providedLDService.application) {
20
+ providedLDService.application = application;
21
+ }
22
+ useEffect(()=>{
23
+ return ()=>{
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
25
+ providedLDService.application = prevApplication.current;
26
+ };
27
+ }, [
28
+ providedLDService
29
+ ]);
30
+ return children;
31
+ });
16
32
 
17
33
  //# sourceMappingURL=ld-service-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ld-service-provider.tsx"],"sourcesContent":["import { provide } from '@servicetitan/react-ioc';\n\nimport { getLDClient } from './get-ld-client';\nimport { LD_SERVICE_TOKEN, LDService } from './types';\n\nconst ldService: LDService = {\n getClient: getLDClient,\n};\n\nexport const LDServiceProvider = provide({\n singletons: [{ provide: LD_SERVICE_TOKEN, useValue: ldService, inherit: true }],\n})(({ children }) => children);\n"],"names":["provide","getLDClient","LD_SERVICE_TOKEN","ldService","getClient","LDServiceProvider","singletons","useValue","inherit","children"],"mappings":"AAAA,SAASA,OAAO,QAAQ,0BAA0B;AAElD,SAASC,WAAW,QAAQ,kBAAkB;AAC9C,SAASC,gBAAgB,QAAmB,UAAU;AAEtD,MAAMC,YAAuB;IACzBC,WAAWH;AACf;AAEA,OAAO,MAAMI,oBAAoBL,QAAQ;IACrCM,YAAY;QAAC;YAAEN,SAASE;YAAkBK,UAAUJ;YAAWK,SAAS;QAAK;KAAE;AACnF,GAAG,CAAC,EAAEC,QAAQ,EAAE,GAAKA,UAAU"}
1
+ {"version":3,"sources":["../src/ld-service-provider.tsx"],"sourcesContent":["import { provide, useDependencies } from '@servicetitan/react-ioc';\nimport { FC, PropsWithChildren, useEffect, useRef } from 'react';\nimport { getLDClient } from './get-ld-client';\nimport { LD_SERVICE_TOKEN, LDApplication, LDService } from './types';\n\nconst ldService: LDService = {\n getClient: getLDClient,\n};\n\ninterface LDServiceProviderProps {\n application?: LDApplication;\n}\n\nexport const LDServiceProvider: FC<PropsWithChildren<LDServiceProviderProps>> = provide({\n singletons: [{ provide: LD_SERVICE_TOKEN, useValue: ldService, inherit: true }],\n})(({ children, application }) => {\n const [providedLDService] = useDependencies(LD_SERVICE_TOKEN);\n const prevApplication = useRef(providedLDService.application);\n\n if (providedLDService === ldService || !providedLDService.application) {\n providedLDService.application = application;\n }\n\n useEffect(() => {\n return () => {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n providedLDService.application = prevApplication.current;\n };\n }, [providedLDService]);\n\n return children;\n});\n"],"names":["provide","useDependencies","useEffect","useRef","getLDClient","LD_SERVICE_TOKEN","ldService","getClient","LDServiceProvider","singletons","useValue","inherit","children","application","providedLDService","prevApplication","current"],"mappings":"AAAA,SAASA,OAAO,EAAEC,eAAe,QAAQ,0BAA0B;AACnE,SAAgCC,SAAS,EAAEC,MAAM,QAAQ,QAAQ;AACjE,SAASC,WAAW,QAAQ,kBAAkB;AAC9C,SAASC,gBAAgB,QAAkC,UAAU;AAErE,MAAMC,YAAuB;IACzBC,WAAWH;AACf;AAMA,OAAO,MAAMI,oBAAmER,QAAQ;IACpFS,YAAY;QAAC;YAAET,SAASK;YAAkBK,UAAUJ;YAAWK,SAAS;QAAK;KAAE;AACnF,GAAG,CAAC,EAAEC,QAAQ,EAAEC,WAAW,EAAE;IACzB,MAAM,CAACC,kBAAkB,GAAGb,gBAAgBI;IAC5C,MAAMU,kBAAkBZ,OAAOW,kBAAkBD,WAAW;IAE5D,IAAIC,sBAAsBR,aAAa,CAACQ,kBAAkBD,WAAW,EAAE;QACnEC,kBAAkBD,WAAW,GAAGA;IACpC;IAEAX,UAAU;QACN,OAAO;YACH,uDAAuD;YACvDY,kBAAkBD,WAAW,GAAGE,gBAAgBC,OAAO;QAC3D;IACJ,GAAG;QAACF;KAAkB;IAEtB,OAAOF;AACX,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"feature-flag-provider.test.d.ts","sourceRoot":"","sources":["../../src/tests/feature-flag-provider.test.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC"}
1
+ {"version":3,"file":"feature-flag-provider.test.d.ts","sourceRoot":"","sources":["../../src/tests/feature-flag-provider.test.tsx"],"names":[],"mappings":"AACA,OAAO,2BAA2B,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import '@testing-library/jest-dom';
3
2
  import { Provider } from '@servicetitan/react-ioc';
3
+ import '@testing-library/jest-dom';
4
4
  import { render, screen } from '@testing-library/react';
5
+ import { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';
5
6
  import { FeatureFlagProvider } from '../feature-flag-provider';
6
7
  import { FeatureFlagStore } from '../feature-flag-store';
7
- import { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';
8
8
  jest.mock('launchdarkly-react-client-sdk', ()=>({
9
9
  useLDClient: jest.fn(),
10
10
  useFlags: jest.fn()
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tests/feature-flag-provider.test.tsx"],"sourcesContent":["import '@testing-library/jest-dom';\nimport { Provider } from '@servicetitan/react-ioc';\nimport { FC } from 'react';\nimport { render, screen } from '@testing-library/react';\n\nimport { FeatureFlagProvider } from '../feature-flag-provider';\nimport { FeatureFlagStore } from '../feature-flag-store';\nimport { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';\n\njest.mock('launchdarkly-react-client-sdk', () => ({\n useLDClient: jest.fn(),\n useFlags: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${FeatureFlagProvider.name}`, () => {\n const flags = { foo: 'bar', baz: 'qux' };\n const componentText = '<Component />';\n const mockFeatureFlagStore = {\n setFlags: jest.fn(),\n };\n\n const Component: FC = () => {\n return componentText;\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.mocked(useLDClient).mockImplementation(() => ({}) as any);\n jest.mocked(useFlags).mockImplementation(() => flags);\n });\n\n const subject = () =>\n render(\n <Provider singletons={[{ provide: FeatureFlagStore, useValue: mockFeatureFlagStore }]}>\n <FeatureFlagProvider>\n <Component />\n </FeatureFlagProvider>\n </Provider>\n );\n\n test('renders children', () => {\n subject();\n\n expect(screen.getByText(componentText)).toBeInTheDocument();\n });\n\n test('sets feature flags in store', () => {\n subject();\n\n expect(mockFeatureFlagStore.setFlags).toHaveBeenCalledWith(flags);\n });\n\n describe('when client is not ready', () => {\n beforeEach(() => jest.mocked(useLDClient).mockReturnValue(undefined));\n\n test('does nothing', () => {\n subject();\n\n expect(screen.queryByText(componentText)).not.toBeInTheDocument();\n expect(mockFeatureFlagStore.setFlags).not.toHaveBeenCalledWith(flags);\n });\n });\n});\n"],"names":["Provider","render","screen","FeatureFlagProvider","FeatureFlagStore","useFlags","useLDClient","jest","mock","fn","describe","name","flags","foo","baz","componentText","mockFeatureFlagStore","setFlags","Component","beforeEach","clearAllMocks","mocked","mockImplementation","subject","singletons","provide","useValue","test","expect","getByText","toBeInTheDocument","toHaveBeenCalledWith","mockReturnValue","undefined","queryByText","not"],"mappings":";AAAA,OAAO,4BAA4B;AACnC,SAASA,QAAQ,QAAQ,0BAA0B;AAEnD,SAASC,MAAM,EAAEC,MAAM,QAAQ,yBAAyB;AAExD,SAASC,mBAAmB,QAAQ,2BAA2B;AAC/D,SAASC,gBAAgB,QAAQ,wBAAwB;AACzD,SAASC,QAAQ,EAAEC,WAAW,QAAQ,gCAAgC;AAEtEC,KAAKC,IAAI,CAAC,iCAAiC,IAAO,CAAA;QAC9CF,aAAaC,KAAKE,EAAE;QACpBJ,UAAUE,KAAKE,EAAE;IACrB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEP,oBAAoBQ,IAAI,EAAE,EAAE;IAC3D,MAAMC,QAAQ;QAAEC,KAAK;QAAOC,KAAK;IAAM;IACvC,MAAMC,gBAAgB;IACtB,MAAMC,uBAAuB;QACzBC,UAAUV,KAAKE,EAAE;IACrB;IAEA,MAAMS,YAAgB;QAClB,OAAOH;IACX;IAEAI,WAAW;QACPZ,KAAKa,aAAa;QAClBb,KAAKc,MAAM,CAACf,aAAagB,kBAAkB,CAAC,IAAO,CAAA,CAAC,CAAA;QACpDf,KAAKc,MAAM,CAAChB,UAAUiB,kBAAkB,CAAC,IAAMV;IACnD;IAEA,MAAMW,UAAU,IACZtB,qBACI,KAACD;YAASwB,YAAY;gBAAC;oBAAEC,SAASrB;oBAAkBsB,UAAUV;gBAAqB;aAAE;sBACjF,cAAA,KAACb;0BACG,cAAA,KAACe;;;IAKjBS,KAAK,oBAAoB;QACrBJ;QAEAK,OAAO1B,OAAO2B,SAAS,CAACd,gBAAgBe,iBAAiB;IAC7D;IAEAH,KAAK,+BAA+B;QAChCJ;QAEAK,OAAOZ,qBAAqBC,QAAQ,EAAEc,oBAAoB,CAACnB;IAC/D;IAEAF,SAAS,4BAA4B;QACjCS,WAAW,IAAMZ,KAAKc,MAAM,CAACf,aAAa0B,eAAe,CAACC;QAE1DN,KAAK,gBAAgB;YACjBJ;YAEAK,OAAO1B,OAAOgC,WAAW,CAACnB,gBAAgBoB,GAAG,CAACL,iBAAiB;YAC/DF,OAAOZ,qBAAqBC,QAAQ,EAAEkB,GAAG,CAACJ,oBAAoB,CAACnB;QACnE;IACJ;AACJ"}
1
+ {"version":3,"sources":["../../src/tests/feature-flag-provider.test.tsx"],"sourcesContent":["import { Provider } from '@servicetitan/react-ioc';\nimport '@testing-library/jest-dom';\nimport { render, screen } from '@testing-library/react';\nimport { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';\nimport { FC } from 'react';\nimport { FeatureFlagProvider } from '../feature-flag-provider';\nimport { FeatureFlagStore } from '../feature-flag-store';\n\njest.mock('launchdarkly-react-client-sdk', () => ({\n useLDClient: jest.fn(),\n useFlags: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${FeatureFlagProvider.name}`, () => {\n const flags = { foo: 'bar', baz: 'qux' };\n const componentText = '<Component />';\n const mockFeatureFlagStore = {\n setFlags: jest.fn(),\n };\n\n const Component: FC = () => {\n return componentText;\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.mocked(useLDClient).mockImplementation(() => ({}) as any);\n jest.mocked(useFlags).mockImplementation(() => flags);\n });\n\n const subject = () =>\n render(\n <Provider singletons={[{ provide: FeatureFlagStore, useValue: mockFeatureFlagStore }]}>\n <FeatureFlagProvider>\n <Component />\n </FeatureFlagProvider>\n </Provider>\n );\n\n test('renders children', () => {\n subject();\n\n expect(screen.getByText(componentText)).toBeInTheDocument();\n });\n\n test('sets feature flags in store', () => {\n subject();\n\n expect(mockFeatureFlagStore.setFlags).toHaveBeenCalledWith(flags);\n });\n\n describe('when client is not ready', () => {\n beforeEach(() => jest.mocked(useLDClient).mockReturnValue(undefined));\n\n test('does nothing', () => {\n subject();\n\n expect(screen.queryByText(componentText)).not.toBeInTheDocument();\n expect(mockFeatureFlagStore.setFlags).not.toHaveBeenCalledWith(flags);\n });\n });\n});\n"],"names":["Provider","render","screen","useFlags","useLDClient","FeatureFlagProvider","FeatureFlagStore","jest","mock","fn","describe","name","flags","foo","baz","componentText","mockFeatureFlagStore","setFlags","Component","beforeEach","clearAllMocks","mocked","mockImplementation","subject","singletons","provide","useValue","test","expect","getByText","toBeInTheDocument","toHaveBeenCalledWith","mockReturnValue","undefined","queryByText","not"],"mappings":";AAAA,SAASA,QAAQ,QAAQ,0BAA0B;AACnD,OAAO,4BAA4B;AACnC,SAASC,MAAM,EAAEC,MAAM,QAAQ,yBAAyB;AACxD,SAASC,QAAQ,EAAEC,WAAW,QAAQ,gCAAgC;AAEtE,SAASC,mBAAmB,QAAQ,2BAA2B;AAC/D,SAASC,gBAAgB,QAAQ,wBAAwB;AAEzDC,KAAKC,IAAI,CAAC,iCAAiC,IAAO,CAAA;QAC9CJ,aAAaG,KAAKE,EAAE;QACpBN,UAAUI,KAAKE,EAAE;IACrB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEL,oBAAoBM,IAAI,EAAE,EAAE;IAC3D,MAAMC,QAAQ;QAAEC,KAAK;QAAOC,KAAK;IAAM;IACvC,MAAMC,gBAAgB;IACtB,MAAMC,uBAAuB;QACzBC,UAAUV,KAAKE,EAAE;IACrB;IAEA,MAAMS,YAAgB;QAClB,OAAOH;IACX;IAEAI,WAAW;QACPZ,KAAKa,aAAa;QAClBb,KAAKc,MAAM,CAACjB,aAAakB,kBAAkB,CAAC,IAAO,CAAA,CAAC,CAAA;QACpDf,KAAKc,MAAM,CAAClB,UAAUmB,kBAAkB,CAAC,IAAMV;IACnD;IAEA,MAAMW,UAAU,IACZtB,qBACI,KAACD;YAASwB,YAAY;gBAAC;oBAAEC,SAASnB;oBAAkBoB,UAAUV;gBAAqB;aAAE;sBACjF,cAAA,KAACX;0BACG,cAAA,KAACa;;;IAKjBS,KAAK,oBAAoB;QACrBJ;QAEAK,OAAO1B,OAAO2B,SAAS,CAACd,gBAAgBe,iBAAiB;IAC7D;IAEAH,KAAK,+BAA+B;QAChCJ;QAEAK,OAAOZ,qBAAqBC,QAAQ,EAAEc,oBAAoB,CAACnB;IAC/D;IAEAF,SAAS,4BAA4B;QACjCS,WAAW,IAAMZ,KAAKc,MAAM,CAACjB,aAAa4B,eAAe,CAACC;QAE1DN,KAAK,gBAAgB;YACjBJ;YAEAK,OAAO1B,OAAOgC,WAAW,CAACnB,gBAAgBoB,GAAG,CAACL,iBAAiB;YAC/DF,OAAOZ,qBAAqBC,QAAQ,EAAEkB,GAAG,CAACJ,oBAAoB,CAACnB;QACnE;IACJ;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tests/get-ld-client.test.ts"],"sourcesContent":["import { initialize } from 'launchdarkly-js-client-sdk';\n\nimport { getLDClient } from '../get-ld-client';\n\njest.mock('launchdarkly-js-client-sdk', () => ({\n initialize: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${getLDClient.name}`, () => {\n const mockClient: any = Symbol('mockClient');\n let config: Parameters<typeof getLDClient>[0];\n\n const subject = () => getLDClient(config);\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.mocked(initialize).mockImplementation(() => mockClient);\n config = { clientSideID: makeId() };\n });\n\n function anonymousUserContext() {\n return { kind: 'user', anonymous: true };\n }\n\n test('returns new LaunchDarkly client with anonymous user context', () => {\n expect(subject()).toBe(mockClient);\n expect(initialize).toHaveBeenCalledWith(\n config.clientSideID,\n anonymousUserContext(),\n undefined\n );\n });\n\n describe('when given a context', () => {\n beforeEach(() => (config.context = { kind: 'multi' }));\n\n test('initializes client with context', () => {\n subject();\n\n expect(initialize).toHaveBeenCalledWith(config.clientSideID, config.context, undefined);\n });\n });\n\n describe('when given options', () => {\n beforeEach(() => (config.options = { hash: 'foo' }));\n\n test('initializes client with options', () => {\n subject();\n\n expect(initialize).toHaveBeenCalledWith(\n config.clientSideID,\n anonymousUserContext(),\n config.options\n );\n });\n });\n\n describe('when client already exists', () => {\n const existingClient: any = Symbol('existingClient');\n\n beforeEach(() => {\n jest.mocked(initialize).mockImplementationOnce(() => existingClient);\n subject();\n });\n\n test('returns existing client', () => {\n expect(subject()).toBe(existingClient);\n expect(initialize).toHaveBeenCalledTimes(1);\n });\n });\n});\n\nfunction makeId() {\n return Math.round(1e6 * Math.random()).toString(36);\n}\n"],"names":["initialize","getLDClient","jest","mock","fn","describe","name","mockClient","Symbol","config","subject","beforeEach","clearAllMocks","mocked","mockImplementation","clientSideID","makeId","anonymousUserContext","kind","anonymous","test","expect","toBe","toHaveBeenCalledWith","undefined","context","options","hash","existingClient","mockImplementationOnce","toHaveBeenCalledTimes","Math","round","random","toString"],"mappings":"AAAA,SAASA,UAAU,QAAQ,6BAA6B;AAExD,SAASC,WAAW,QAAQ,mBAAmB;AAE/CC,KAAKC,IAAI,CAAC,8BAA8B,IAAO,CAAA;QAC3CH,YAAYE,KAAKE,EAAE;IACvB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEJ,YAAYK,IAAI,EAAE,EAAE;IACnD,MAAMC,aAAkBC,OAAO;IAC/B,IAAIC;IAEJ,MAAMC,UAAU,IAAMT,YAAYQ;IAElCE,WAAW;QACPT,KAAKU,aAAa;QAClBV,KAAKW,MAAM,CAACb,YAAYc,kBAAkB,CAAC,IAAMP;QACjDE,SAAS;YAAEM,cAAcC;QAAS;IACtC;IAEA,SAASC;QACL,OAAO;YAAEC,MAAM;YAAQC,WAAW;QAAK;IAC3C;IAEAC,KAAK,+DAA+D;QAChEC,OAAOX,WAAWY,IAAI,CAACf;QACvBc,OAAOrB,YAAYuB,oBAAoB,CACnCd,OAAOM,YAAY,EACnBE,wBACAO;IAER;IAEAnB,SAAS,wBAAwB;QAC7BM,WAAW,IAAOF,OAAOgB,OAAO,GAAG;gBAAEP,MAAM;YAAQ;QAEnDE,KAAK,mCAAmC;YACpCV;YAEAW,OAAOrB,YAAYuB,oBAAoB,CAACd,OAAOM,YAAY,EAAEN,OAAOgB,OAAO,EAAED;QACjF;IACJ;IAEAnB,SAAS,sBAAsB;QAC3BM,WAAW,IAAOF,OAAOiB,OAAO,GAAG;gBAAEC,MAAM;YAAM;QAEjDP,KAAK,mCAAmC;YACpCV;YAEAW,OAAOrB,YAAYuB,oBAAoB,CACnCd,OAAOM,YAAY,EACnBE,wBACAR,OAAOiB,OAAO;QAEtB;IACJ;IAEArB,SAAS,8BAA8B;QACnC,MAAMuB,iBAAsBpB,OAAO;QAEnCG,WAAW;YACPT,KAAKW,MAAM,CAACb,YAAY6B,sBAAsB,CAAC,IAAMD;YACrDlB;QACJ;QAEAU,KAAK,2BAA2B;YAC5BC,OAAOX,WAAWY,IAAI,CAACM;YACvBP,OAAOrB,YAAY8B,qBAAqB,CAAC;QAC7C;IACJ;AACJ;AAEA,SAASd;IACL,OAAOe,KAAKC,KAAK,CAAC,MAAMD,KAAKE,MAAM,IAAIC,QAAQ,CAAC;AACpD"}
1
+ {"version":3,"sources":["../../src/tests/get-ld-client.test.ts"],"sourcesContent":["import { initialize } from 'launchdarkly-js-client-sdk';\nimport { getLDClient } from '../get-ld-client';\n\njest.mock('launchdarkly-js-client-sdk', () => ({\n initialize: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${getLDClient.name}`, () => {\n const mockClient: any = Symbol('mockClient');\n let config: Parameters<typeof getLDClient>[0];\n\n const subject = () => getLDClient(config);\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.mocked(initialize).mockImplementation(() => mockClient);\n config = { clientSideID: makeId() };\n });\n\n function anonymousUserContext() {\n return { kind: 'user', anonymous: true };\n }\n\n test('returns new LaunchDarkly client with anonymous user context', () => {\n expect(subject()).toBe(mockClient);\n expect(initialize).toHaveBeenCalledWith(\n config.clientSideID,\n anonymousUserContext(),\n undefined\n );\n });\n\n describe('when given a context', () => {\n beforeEach(() => (config.context = { kind: 'multi' }));\n\n test('initializes client with context', () => {\n subject();\n\n expect(initialize).toHaveBeenCalledWith(config.clientSideID, config.context, undefined);\n });\n });\n\n describe('when given options', () => {\n beforeEach(() => (config.options = { hash: 'foo' }));\n\n test('initializes client with options', () => {\n subject();\n\n expect(initialize).toHaveBeenCalledWith(\n config.clientSideID,\n anonymousUserContext(),\n config.options\n );\n });\n });\n\n describe('when client already exists', () => {\n const existingClient: any = Symbol('existingClient');\n\n beforeEach(() => {\n jest.mocked(initialize).mockImplementationOnce(() => existingClient);\n subject();\n });\n\n test('returns existing client', () => {\n expect(subject()).toBe(existingClient);\n expect(initialize).toHaveBeenCalledTimes(1);\n });\n });\n});\n\nfunction makeId() {\n return Math.round(1e6 * Math.random()).toString(36);\n}\n"],"names":["initialize","getLDClient","jest","mock","fn","describe","name","mockClient","Symbol","config","subject","beforeEach","clearAllMocks","mocked","mockImplementation","clientSideID","makeId","anonymousUserContext","kind","anonymous","test","expect","toBe","toHaveBeenCalledWith","undefined","context","options","hash","existingClient","mockImplementationOnce","toHaveBeenCalledTimes","Math","round","random","toString"],"mappings":"AAAA,SAASA,UAAU,QAAQ,6BAA6B;AACxD,SAASC,WAAW,QAAQ,mBAAmB;AAE/CC,KAAKC,IAAI,CAAC,8BAA8B,IAAO,CAAA;QAC3CH,YAAYE,KAAKE,EAAE;IACvB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEJ,YAAYK,IAAI,EAAE,EAAE;IACnD,MAAMC,aAAkBC,OAAO;IAC/B,IAAIC;IAEJ,MAAMC,UAAU,IAAMT,YAAYQ;IAElCE,WAAW;QACPT,KAAKU,aAAa;QAClBV,KAAKW,MAAM,CAACb,YAAYc,kBAAkB,CAAC,IAAMP;QACjDE,SAAS;YAAEM,cAAcC;QAAS;IACtC;IAEA,SAASC;QACL,OAAO;YAAEC,MAAM;YAAQC,WAAW;QAAK;IAC3C;IAEAC,KAAK,+DAA+D;QAChEC,OAAOX,WAAWY,IAAI,CAACf;QACvBc,OAAOrB,YAAYuB,oBAAoB,CACnCd,OAAOM,YAAY,EACnBE,wBACAO;IAER;IAEAnB,SAAS,wBAAwB;QAC7BM,WAAW,IAAOF,OAAOgB,OAAO,GAAG;gBAAEP,MAAM;YAAQ;QAEnDE,KAAK,mCAAmC;YACpCV;YAEAW,OAAOrB,YAAYuB,oBAAoB,CAACd,OAAOM,YAAY,EAAEN,OAAOgB,OAAO,EAAED;QACjF;IACJ;IAEAnB,SAAS,sBAAsB;QAC3BM,WAAW,IAAOF,OAAOiB,OAAO,GAAG;gBAAEC,MAAM;YAAM;QAEjDP,KAAK,mCAAmC;YACpCV;YAEAW,OAAOrB,YAAYuB,oBAAoB,CACnCd,OAAOM,YAAY,EACnBE,wBACAR,OAAOiB,OAAO;QAEtB;IACJ;IAEArB,SAAS,8BAA8B;QACnC,MAAMuB,iBAAsBpB,OAAO;QAEnCG,WAAW;YACPT,KAAKW,MAAM,CAACb,YAAY6B,sBAAsB,CAAC,IAAMD;YACrDlB;QACJ;QAEAU,KAAK,2BAA2B;YAC5BC,OAAOX,WAAWY,IAAI,CAACM;YACvBP,OAAOrB,YAAY8B,qBAAqB,CAAC;QAC7C;IACJ;AACJ;AAEA,SAASd;IACL,OAAOe,KAAKC,KAAK,CAAC,MAAMD,KAAKE,MAAM,IAAIC,QAAQ,CAAC;AACpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"ld-provider.test.d.ts","sourceRoot":"","sources":["../../src/tests/ld-provider.test.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC"}
1
+ {"version":3,"file":"ld-provider.test.d.ts","sourceRoot":"","sources":["../../src/tests/ld-provider.test.tsx"],"names":[],"mappings":"AAEA,OAAO,2BAA2B,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import '@testing-library/jest-dom';
3
2
  import { Log } from '@servicetitan/log-service';
4
3
  import { Provider, useDependencies } from '@servicetitan/react-ioc';
4
+ import '@testing-library/jest-dom';
5
5
  import { render, screen, waitFor } from '@testing-library/react';
6
6
  import { act, Fragment } from 'react';
7
7
  import { FeatureFlagStore } from '../feature-flag-store';
@@ -159,10 +159,11 @@ describe(`[launchdarkly-service] ${LDProvider.name}`, ()=>{
159
159
  waitForInitialization: jest.fn().mockResolvedValue(undefined),
160
160
  toString: ()=>'ldServiceClient'
161
161
  };
162
- const ldService = {
163
- getClient: jest.fn().mockReturnValue(ldServiceClient)
164
- };
162
+ let ldService;
165
163
  beforeEach(()=>{
164
+ ldService = {
165
+ getClient: jest.fn().mockReturnValue(ldServiceClient)
166
+ };
166
167
  singletons === null || singletons === void 0 ? void 0 : singletons.push({
167
168
  provide: LD_SERVICE_TOKEN,
168
169
  useValue: ldService
@@ -176,6 +177,22 @@ describe(`[launchdarkly-service] ${LDProvider.name}`, ()=>{
176
177
  }));
177
178
  expect(ldServiceClient.waitForInitialization).toHaveBeenCalled();
178
179
  });
180
+ describe('when application is provided', ()=>{
181
+ const application = {
182
+ id: 'some-application',
183
+ version: '1.2.3'
184
+ };
185
+ beforeEach(()=>ldService.application = application);
186
+ test('passes application to LDClient', async ()=>{
187
+ subject();
188
+ await waitFor(()=>expectLDProvider());
189
+ expect(ldService.getClient).toHaveBeenCalledWith(expect.objectContaining({
190
+ options: {
191
+ application
192
+ }
193
+ }));
194
+ });
195
+ });
179
196
  });
180
197
  });
181
198
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tests/ld-provider.test.tsx"],"sourcesContent":["import '@testing-library/jest-dom';\nimport { Log } from '@servicetitan/log-service';\nimport { Provider, useDependencies } from '@servicetitan/react-ioc';\nimport { render, screen, waitFor } from '@testing-library/react';\nimport { LDClient } from 'launchdarkly-js-client-sdk';\nimport { act, FC, Fragment } from 'react';\n\nimport { FeatureFlagStore } from '../feature-flag-store';\nimport { getLDClient } from '../get-ld-client';\nimport { LDProvider } from '../ld-provider';\nimport { LD_SERVICE_TOKEN, LDService } from '../types';\n\nfunction formatProps(props: Record<string, any>) {\n return Object.entries(props).map(([key, value]) => {\n return `${key}=${value.toString()}`;\n });\n}\n\nfunction mockComponent(name: string) {\n return {\n [name]: ({ children, ...props }: any) => (\n <Fragment>\n <div>{`<${name} ${formatProps(props)} />`}</div>\n {children}\n </Fragment>\n ),\n };\n}\n\njest.mock('launchdarkly-react-client-sdk', () => ({\n ...mockComponent('LDProvider'),\n}));\njest.mock('../feature-flag-provider', () => ({\n ...mockComponent('FeatureFlagProvider'),\n}));\njest.mock('../get-ld-client', () => ({\n getLDClient: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${LDProvider.name}`, () => {\n const log: Partial<Log> = {\n error: jest.fn(),\n };\n const ldClient: Partial<LDClient> & { toString: () => string } = {\n on: jest.fn(),\n off: jest.fn(),\n waitUntilReady: jest.fn().mockResolvedValue(undefined),\n waitForInitialization: jest.fn().mockResolvedValue(undefined),\n toString: () => 'ldClient',\n };\n let singletons: Required<Parameters<typeof Provider>[0]>['singletons'];\n let props: Parameters<typeof LDProvider>[0];\n let providedFeatureFlagStore: FeatureFlagStore;\n let renderCount: number;\n\n const Component: FC = () => {\n [providedFeatureFlagStore] = useDependencies(FeatureFlagStore);\n renderCount += 1;\n return <div>{'<Component />'}</div>;\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.mocked(getLDClient).mockReturnValue(ldClient as LDClient);\n renderCount = 0;\n singletons = [];\n props = { clientSideID: 'foo', projectName: 'bar' };\n });\n\n const subject = () => {\n return render(\n <Provider singletons={singletons}>\n <LDProvider {...props}>\n <Component />\n </LDProvider>\n </Provider>\n );\n };\n\n function expectLDProvider(props?: Record<string, any>) {\n if (props) {\n expect(screen.getByText(`<LDProvider ${formatProps(props)} />`)).toBeInTheDocument();\n } else {\n expect(screen.getByText(/<LDProvider .* \\/>/)).toBeInTheDocument();\n }\n }\n\n test('renders base LDProvider and FeatureFlagProvider after client is ready and initialized', async () => {\n subject();\n\n await waitFor(() => expectLDProvider({ clientSideID: props.clientSideID, ldClient }));\n\n expect(screen.getByText('<FeatureFlagProvider />')).toBeInTheDocument();\n expect(screen.getByText('<Component />')).toBeInTheDocument();\n expect(ldClient.waitForInitialization).toHaveBeenCalled();\n });\n\n test('provides FeatureFlagStore', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(providedFeatureFlagStore).toBeDefined();\n });\n\n describe('when waitForInitialization is false', () => {\n let initializedCallback: Function;\n\n beforeEach(() => {\n props.waitForInitialization = false;\n jest.mocked(ldClient.on)?.mockImplementation((event, callback) => {\n if (event === 'initialized') {\n initializedCallback = callback;\n }\n });\n });\n\n test('does not wait for client to initialize', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(ldClient.waitForInitialization).not.toHaveBeenCalled();\n });\n\n test('re-renders when client is initialized', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n expect(renderCount).toBe(1);\n\n act(() => initializedCallback?.());\n expect(renderCount).toBe(2);\n });\n\n test('deregisters listener when component is unmounted', async () => {\n const { unmount } = subject();\n\n await waitFor(() => expectLDProvider());\n\n unmount();\n\n expect(jest.mocked(ldClient.off)).toHaveBeenCalledWith(\n 'initialized',\n initializedCallback\n );\n });\n });\n\n describe('when initialization fails', () => {\n beforeEach(() => {\n jest.mocked(ldClient.waitForInitialization)?.mockRejectedValue('Oops!');\n });\n\n test('renders base LDProvider', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n });\n\n describe('when log service is provided', () => {\n beforeEach(() => singletons.push({ provide: Log, useValue: log }));\n\n test('logs error', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(log.error).toHaveBeenCalledWith({\n category: 'LaunchDarkly',\n code: 'InitializationFailed',\n error: 'Oops!',\n message: `\"${props.projectName}\" client failed to initialize`,\n });\n });\n });\n });\n\n describe('when LDService is provided', () => {\n const ldServiceClient: Partial<LDClient> & { toString: () => string } = {\n waitUntilReady: jest.fn().mockResolvedValue(undefined),\n waitForInitialization: jest.fn().mockResolvedValue(undefined),\n toString: () => 'ldServiceClient',\n };\n const ldService: LDService = {\n getClient: jest.fn().mockReturnValue(ldServiceClient),\n };\n\n beforeEach(() => {\n singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: ldService });\n });\n\n test('uses LDService client', async () => {\n subject();\n\n await waitFor(() =>\n expectLDProvider({ clientSideID: props.clientSideID, ldClient: ldServiceClient })\n );\n\n expect(ldServiceClient.waitForInitialization).toHaveBeenCalled();\n });\n });\n});\n"],"names":["Log","Provider","useDependencies","render","screen","waitFor","act","Fragment","FeatureFlagStore","getLDClient","LDProvider","LD_SERVICE_TOKEN","formatProps","props","Object","entries","map","key","value","toString","mockComponent","name","children","div","jest","mock","fn","describe","log","error","ldClient","on","off","waitUntilReady","mockResolvedValue","undefined","waitForInitialization","singletons","providedFeatureFlagStore","renderCount","Component","beforeEach","clearAllMocks","mocked","mockReturnValue","clientSideID","projectName","subject","expectLDProvider","expect","getByText","toBeInTheDocument","test","toHaveBeenCalled","toBeDefined","initializedCallback","mockImplementation","event","callback","not","toBe","unmount","toHaveBeenCalledWith","mockRejectedValue","push","provide","useValue","category","code","message","ldServiceClient","ldService","getClient"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/tests/ld-provider.test.tsx"],"sourcesContent":["import { Log } from '@servicetitan/log-service';\nimport { Provider, useDependencies } from '@servicetitan/react-ioc';\nimport '@testing-library/jest-dom';\nimport { render, screen, waitFor } from '@testing-library/react';\nimport { LDClient } from 'launchdarkly-js-client-sdk';\nimport { act, FC, Fragment } from 'react';\nimport { FeatureFlagStore } from '../feature-flag-store';\nimport { getLDClient } from '../get-ld-client';\nimport { LDProvider } from '../ld-provider';\nimport { LD_SERVICE_TOKEN, LDService } from '../types';\n\nfunction formatProps(props: Record<string, any>) {\n return Object.entries(props).map(([key, value]) => {\n return `${key}=${value.toString()}`;\n });\n}\n\nfunction mockComponent(name: string) {\n return {\n [name]: ({ children, ...props }: any) => (\n <Fragment>\n <div>{`<${name} ${formatProps(props)} />`}</div>\n {children}\n </Fragment>\n ),\n };\n}\n\njest.mock('launchdarkly-react-client-sdk', () => ({\n ...mockComponent('LDProvider'),\n}));\njest.mock('../feature-flag-provider', () => ({\n ...mockComponent('FeatureFlagProvider'),\n}));\njest.mock('../get-ld-client', () => ({\n getLDClient: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${LDProvider.name}`, () => {\n const log: Partial<Log> = {\n error: jest.fn(),\n };\n const ldClient: Partial<LDClient> & { toString: () => string } = {\n on: jest.fn(),\n off: jest.fn(),\n waitUntilReady: jest.fn().mockResolvedValue(undefined),\n waitForInitialization: jest.fn().mockResolvedValue(undefined),\n toString: () => 'ldClient',\n };\n let singletons: Required<Parameters<typeof Provider>[0]>['singletons'];\n let props: Parameters<typeof LDProvider>[0];\n let providedFeatureFlagStore: FeatureFlagStore;\n let renderCount: number;\n\n const Component: FC = () => {\n [providedFeatureFlagStore] = useDependencies(FeatureFlagStore);\n renderCount += 1;\n return <div>{'<Component />'}</div>;\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n jest.mocked(getLDClient).mockReturnValue(ldClient as LDClient);\n renderCount = 0;\n singletons = [];\n props = { clientSideID: 'foo', projectName: 'bar' };\n });\n\n const subject = () => {\n return render(\n <Provider singletons={singletons}>\n <LDProvider {...props}>\n <Component />\n </LDProvider>\n </Provider>\n );\n };\n\n function expectLDProvider(props?: Record<string, any>) {\n if (props) {\n expect(screen.getByText(`<LDProvider ${formatProps(props)} />`)).toBeInTheDocument();\n } else {\n expect(screen.getByText(/<LDProvider .* \\/>/)).toBeInTheDocument();\n }\n }\n\n test('renders base LDProvider and FeatureFlagProvider after client is ready and initialized', async () => {\n subject();\n\n await waitFor(() => expectLDProvider({ clientSideID: props.clientSideID, ldClient }));\n\n expect(screen.getByText('<FeatureFlagProvider />')).toBeInTheDocument();\n expect(screen.getByText('<Component />')).toBeInTheDocument();\n expect(ldClient.waitForInitialization).toHaveBeenCalled();\n });\n\n test('provides FeatureFlagStore', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(providedFeatureFlagStore).toBeDefined();\n });\n\n describe('when waitForInitialization is false', () => {\n let initializedCallback: Function;\n\n beforeEach(() => {\n props.waitForInitialization = false;\n jest.mocked(ldClient.on)?.mockImplementation((event, callback) => {\n if (event === 'initialized') {\n initializedCallback = callback;\n }\n });\n });\n\n test('does not wait for client to initialize', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(ldClient.waitForInitialization).not.toHaveBeenCalled();\n });\n\n test('re-renders when client is initialized', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n expect(renderCount).toBe(1);\n\n act(() => initializedCallback?.());\n expect(renderCount).toBe(2);\n });\n\n test('deregisters listener when component is unmounted', async () => {\n const { unmount } = subject();\n\n await waitFor(() => expectLDProvider());\n\n unmount();\n\n expect(jest.mocked(ldClient.off)).toHaveBeenCalledWith(\n 'initialized',\n initializedCallback\n );\n });\n });\n\n describe('when initialization fails', () => {\n beforeEach(() => {\n jest.mocked(ldClient.waitForInitialization)?.mockRejectedValue('Oops!');\n });\n\n test('renders base LDProvider', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n });\n\n describe('when log service is provided', () => {\n beforeEach(() => singletons.push({ provide: Log, useValue: log }));\n\n test('logs error', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(log.error).toHaveBeenCalledWith({\n category: 'LaunchDarkly',\n code: 'InitializationFailed',\n error: 'Oops!',\n message: `\"${props.projectName}\" client failed to initialize`,\n });\n });\n });\n });\n\n describe('when LDService is provided', () => {\n const ldServiceClient: Partial<LDClient> & { toString: () => string } = {\n waitUntilReady: jest.fn().mockResolvedValue(undefined),\n waitForInitialization: jest.fn().mockResolvedValue(undefined),\n toString: () => 'ldServiceClient',\n };\n let ldService: LDService;\n\n beforeEach(() => {\n ldService = { getClient: jest.fn().mockReturnValue(ldServiceClient) };\n singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: ldService });\n });\n\n test('uses LDService client', async () => {\n subject();\n\n await waitFor(() =>\n expectLDProvider({ clientSideID: props.clientSideID, ldClient: ldServiceClient })\n );\n\n expect(ldServiceClient.waitForInitialization).toHaveBeenCalled();\n });\n\n describe('when application is provided', () => {\n const application = { id: 'some-application', version: '1.2.3' };\n\n beforeEach(() => (ldService.application = application));\n\n test('passes application to LDClient', async () => {\n subject();\n\n await waitFor(() => expectLDProvider());\n\n expect(ldService.getClient).toHaveBeenCalledWith(\n expect.objectContaining({\n options: { application },\n })\n );\n });\n });\n });\n});\n"],"names":["Log","Provider","useDependencies","render","screen","waitFor","act","Fragment","FeatureFlagStore","getLDClient","LDProvider","LD_SERVICE_TOKEN","formatProps","props","Object","entries","map","key","value","toString","mockComponent","name","children","div","jest","mock","fn","describe","log","error","ldClient","on","off","waitUntilReady","mockResolvedValue","undefined","waitForInitialization","singletons","providedFeatureFlagStore","renderCount","Component","beforeEach","clearAllMocks","mocked","mockReturnValue","clientSideID","projectName","subject","expectLDProvider","expect","getByText","toBeInTheDocument","test","toHaveBeenCalled","toBeDefined","initializedCallback","mockImplementation","event","callback","not","toBe","unmount","toHaveBeenCalledWith","mockRejectedValue","push","provide","useValue","category","code","message","ldServiceClient","ldService","getClient","application","id","version","objectContaining","options"],"mappings":";AAAA,SAASA,GAAG,QAAQ,4BAA4B;AAChD,SAASC,QAAQ,EAAEC,eAAe,QAAQ,0BAA0B;AACpE,OAAO,4BAA4B;AACnC,SAASC,MAAM,EAAEC,MAAM,EAAEC,OAAO,QAAQ,yBAAyB;AAEjE,SAASC,GAAG,EAAMC,QAAQ,QAAQ,QAAQ;AAC1C,SAASC,gBAAgB,QAAQ,wBAAwB;AACzD,SAASC,WAAW,QAAQ,mBAAmB;AAC/C,SAASC,UAAU,QAAQ,iBAAiB;AAC5C,SAASC,gBAAgB,QAAmB,WAAW;AAEvD,SAASC,YAAYC,KAA0B;IAC3C,OAAOC,OAAOC,OAAO,CAACF,OAAOG,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM;QAC1C,OAAO,GAAGD,IAAI,CAAC,EAAEC,MAAMC,QAAQ,IAAI;IACvC;AACJ;AAEA,SAASC,cAAcC,IAAY;IAC/B,OAAO;QACH,CAACA,KAAK,EAAE,CAAC,EAAEC,QAAQ,EAAE,GAAGT,OAAY,iBAChC,MAACN;;kCACG,KAACgB;kCAAK,CAAC,CAAC,EAAEF,KAAK,CAAC,EAAET,YAAYC,OAAO,GAAG,CAAC;;oBACxCS;;;IAGb;AACJ;AAEAE,KAAKC,IAAI,CAAC,iCAAiC,IAAO,CAAA;QAC9C,GAAGL,cAAc,aAAa;IAClC,CAAA;AACAI,KAAKC,IAAI,CAAC,4BAA4B,IAAO,CAAA;QACzC,GAAGL,cAAc,sBAAsB;IAC3C,CAAA;AACAI,KAAKC,IAAI,CAAC,oBAAoB,IAAO,CAAA;QACjChB,aAAae,KAAKE,EAAE;IACxB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEjB,WAAWW,IAAI,EAAE,EAAE;IAClD,MAAMO,MAAoB;QACtBC,OAAOL,KAAKE,EAAE;IAClB;IACA,MAAMI,WAA2D;QAC7DC,IAAIP,KAAKE,EAAE;QACXM,KAAKR,KAAKE,EAAE;QACZO,gBAAgBT,KAAKE,EAAE,GAAGQ,iBAAiB,CAACC;QAC5CC,uBAAuBZ,KAAKE,EAAE,GAAGQ,iBAAiB,CAACC;QACnDhB,UAAU,IAAM;IACpB;IACA,IAAIkB;IACJ,IAAIxB;IACJ,IAAIyB;IACJ,IAAIC;IAEJ,MAAMC,YAAgB;QAClB,CAACF,yBAAyB,GAAGpC,gBAAgBM;QAC7C+B,eAAe;QACf,qBAAO,KAAChB;sBAAK;;IACjB;IAEAkB,WAAW;QACPjB,KAAKkB,aAAa;QAClBlB,KAAKmB,MAAM,CAAClC,aAAamC,eAAe,CAACd;QACzCS,cAAc;QACdF,aAAa,EAAE;QACfxB,QAAQ;YAAEgC,cAAc;YAAOC,aAAa;QAAM;IACtD;IAEA,MAAMC,UAAU;QACZ,OAAO5C,qBACH,KAACF;YAASoC,YAAYA;sBAClB,cAAA,KAAC3B;gBAAY,GAAGG,KAAK;0BACjB,cAAA,KAAC2B;;;IAIjB;IAEA,SAASQ,iBAAiBnC,KAA2B;QACjD,IAAIA,OAAO;YACPoC,OAAO7C,OAAO8C,SAAS,CAAC,CAAC,YAAY,EAAEtC,YAAYC,OAAO,GAAG,CAAC,GAAGsC,iBAAiB;QACtF,OAAO;YACHF,OAAO7C,OAAO8C,SAAS,CAAC,uBAAuBC,iBAAiB;QACpE;IACJ;IAEAC,KAAK,yFAAyF;QAC1FL;QAEA,MAAM1C,QAAQ,IAAM2C,iBAAiB;gBAAEH,cAAchC,MAAMgC,YAAY;gBAAEf;YAAS;QAElFmB,OAAO7C,OAAO8C,SAAS,CAAC,4BAA4BC,iBAAiB;QACrEF,OAAO7C,OAAO8C,SAAS,CAAC,kBAAkBC,iBAAiB;QAC3DF,OAAOnB,SAASM,qBAAqB,EAAEiB,gBAAgB;IAC3D;IAEAD,KAAK,6BAA6B;QAC9BL;QAEA,MAAM1C,QAAQ,IAAM2C;QAEpBC,OAAOX,0BAA0BgB,WAAW;IAChD;IAEA3B,SAAS,uCAAuC;QAC5C,IAAI4B;QAEJd,WAAW;gBAEPjB;YADAX,MAAMuB,qBAAqB,GAAG;aAC9BZ,eAAAA,KAAKmB,MAAM,CAACb,SAASC,EAAE,eAAvBP,mCAAAA,aAA0BgC,kBAAkB,CAAC,CAACC,OAAOC;gBACjD,IAAID,UAAU,eAAe;oBACzBF,sBAAsBG;gBAC1B;YACJ;QACJ;QAEAN,KAAK,0CAA0C;YAC3CL;YAEA,MAAM1C,QAAQ,IAAM2C;YAEpBC,OAAOnB,SAASM,qBAAqB,EAAEuB,GAAG,CAACN,gBAAgB;QAC/D;QAEAD,KAAK,yCAAyC;YAC1CL;YAEA,MAAM1C,QAAQ,IAAM2C;YACpBC,OAAOV,aAAaqB,IAAI,CAAC;YAEzBtD,IAAI,IAAMiD,gCAAAA,0CAAAA;YACVN,OAAOV,aAAaqB,IAAI,CAAC;QAC7B;QAEAR,KAAK,oDAAoD;YACrD,MAAM,EAAES,OAAO,EAAE,GAAGd;YAEpB,MAAM1C,QAAQ,IAAM2C;YAEpBa;YAEAZ,OAAOzB,KAAKmB,MAAM,CAACb,SAASE,GAAG,GAAG8B,oBAAoB,CAClD,eACAP;QAER;IACJ;IAEA5B,SAAS,6BAA6B;QAClCc,WAAW;gBACPjB;aAAAA,eAAAA,KAAKmB,MAAM,CAACb,SAASM,qBAAqB,eAA1CZ,mCAAAA,aAA6CuC,iBAAiB,CAAC;QACnE;QAEAX,KAAK,2BAA2B;YAC5BL;YAEA,MAAM1C,QAAQ,IAAM2C;QACxB;QAEArB,SAAS,gCAAgC;YACrCc,WAAW,IAAMJ,WAAW2B,IAAI,CAAC;oBAAEC,SAASjE;oBAAKkE,UAAUtC;gBAAI;YAE/DwB,KAAK,cAAc;gBACfL;gBAEA,MAAM1C,QAAQ,IAAM2C;gBAEpBC,OAAOrB,IAAIC,KAAK,EAAEiC,oBAAoB,CAAC;oBACnCK,UAAU;oBACVC,MAAM;oBACNvC,OAAO;oBACPwC,SAAS,CAAC,CAAC,EAAExD,MAAMiC,WAAW,CAAC,6BAA6B,CAAC;gBACjE;YACJ;QACJ;IACJ;IAEAnB,SAAS,8BAA8B;QACnC,MAAM2C,kBAAkE;YACpErC,gBAAgBT,KAAKE,EAAE,GAAGQ,iBAAiB,CAACC;YAC5CC,uBAAuBZ,KAAKE,EAAE,GAAGQ,iBAAiB,CAACC;YACnDhB,UAAU,IAAM;QACpB;QACA,IAAIoD;QAEJ9B,WAAW;YACP8B,YAAY;gBAAEC,WAAWhD,KAAKE,EAAE,GAAGkB,eAAe,CAAC0B;YAAiB;YACpEjC,uBAAAA,iCAAAA,WAAY2B,IAAI,CAAC;gBAAEC,SAAStD;gBAAkBuD,UAAUK;YAAU;QACtE;QAEAnB,KAAK,yBAAyB;YAC1BL;YAEA,MAAM1C,QAAQ,IACV2C,iBAAiB;oBAAEH,cAAchC,MAAMgC,YAAY;oBAAEf,UAAUwC;gBAAgB;YAGnFrB,OAAOqB,gBAAgBlC,qBAAqB,EAAEiB,gBAAgB;QAClE;QAEA1B,SAAS,gCAAgC;YACrC,MAAM8C,cAAc;gBAAEC,IAAI;gBAAoBC,SAAS;YAAQ;YAE/DlC,WAAW,IAAO8B,UAAUE,WAAW,GAAGA;YAE1CrB,KAAK,kCAAkC;gBACnCL;gBAEA,MAAM1C,QAAQ,IAAM2C;gBAEpBC,OAAOsB,UAAUC,SAAS,EAAEV,oBAAoB,CAC5Cb,OAAO2B,gBAAgB,CAAC;oBACpBC,SAAS;wBAAEJ;oBAAY;gBAC3B;YAER;QACJ;IACJ;AACJ"}
@@ -5,17 +5,24 @@ import { getLDClient } from '../get-ld-client';
5
5
  import { LDServiceProvider } from '../ld-service-provider';
6
6
  import { LD_SERVICE_TOKEN } from '../types';
7
7
  describe(`[launchdarkly-service] ${LDServiceProvider.name}`, ()=>{
8
+ let providedApplication;
8
9
  let providedLDService;
9
10
  let singletons;
11
+ let props;
10
12
  const Component = ()=>{
11
13
  [providedLDService] = useDependencies(LD_SERVICE_TOKEN);
14
+ providedApplication = providedLDService.application;
12
15
  return null;
13
16
  };
14
- beforeEach(()=>singletons = []);
17
+ beforeEach(()=>{
18
+ singletons = [];
19
+ props = {};
20
+ });
15
21
  const subject = ()=>{
16
22
  return render(/*#__PURE__*/ _jsx(Provider, {
17
23
  singletons: singletons,
18
24
  children: /*#__PURE__*/ _jsx(LDServiceProvider, {
25
+ ...props,
19
26
  children: /*#__PURE__*/ _jsx(Component, {})
20
27
  })
21
28
  }));
@@ -26,8 +33,14 @@ describe(`[launchdarkly-service] ${LDServiceProvider.name}`, ()=>{
26
33
  getClient: getLDClient
27
34
  });
28
35
  });
36
+ test('provides no application', ()=>{
37
+ subject();
38
+ expect(providedApplication).toBeUndefined();
39
+ });
29
40
  describe('when LDService is already provided', ()=>{
30
- const ldService = Symbol('ldService');
41
+ const ldService = {
42
+ getClient: jest.fn()
43
+ };
31
44
  beforeEach(()=>singletons === null || singletons === void 0 ? void 0 : singletons.push({
32
45
  provide: LD_SERVICE_TOKEN,
33
46
  useValue: ldService
@@ -37,6 +50,80 @@ describe(`[launchdarkly-service] ${LDServiceProvider.name}`, ()=>{
37
50
  expect(providedLDService).toBe(ldService);
38
51
  });
39
52
  });
53
+ describe('with "application" prop', ()=>{
54
+ const application = {
55
+ id: 'some-application',
56
+ version: '1.0.0'
57
+ };
58
+ beforeEach(()=>props.application = application);
59
+ function itProvidesApplication() {
60
+ test('provides application', ()=>{
61
+ subject();
62
+ expect(providedApplication).toBe(application);
63
+ });
64
+ }
65
+ itProvidesApplication();
66
+ describe('when rerendered with new application', ()=>{
67
+ const newApplication = {
68
+ id: 'foo'
69
+ };
70
+ beforeEach(()=>{
71
+ const { rerender } = subject();
72
+ rerender(/*#__PURE__*/ _jsx(LDServiceProvider, {
73
+ application: newApplication,
74
+ children: /*#__PURE__*/ _jsx(Component, {})
75
+ }));
76
+ });
77
+ test('provides new application', ()=>{
78
+ expect(providedApplication).toBe(newApplication);
79
+ });
80
+ });
81
+ describe('when rerendered without application', ()=>{
82
+ beforeEach(()=>{
83
+ const { rerender } = subject();
84
+ rerender(/*#__PURE__*/ _jsx(LDServiceProvider, {
85
+ children: /*#__PURE__*/ _jsx(Component, {})
86
+ }));
87
+ });
88
+ test('drops application', ()=>{
89
+ expect(providedApplication).toBeUndefined();
90
+ });
91
+ });
92
+ describe('when LDService is already provided', ()=>{
93
+ let providedLDService;
94
+ beforeEach(()=>{
95
+ providedLDService = {
96
+ getClient: jest.fn()
97
+ };
98
+ singletons === null || singletons === void 0 ? void 0 : singletons.push({
99
+ provide: LD_SERVICE_TOKEN,
100
+ useValue: providedLDService
101
+ });
102
+ });
103
+ itProvidesApplication();
104
+ test('unmount resets LDService.application', ()=>{
105
+ const { unmount } = subject();
106
+ unmount();
107
+ expect(providedLDService.application).toBeUndefined();
108
+ });
109
+ describe('when provided LDService has application', ()=>{
110
+ const otherApplication = {
111
+ id: 'other-application',
112
+ version: '2.0.0'
113
+ };
114
+ beforeEach(()=>providedLDService.application = otherApplication);
115
+ test('provides inherited application', ()=>{
116
+ subject();
117
+ expect(providedApplication).toBe(otherApplication);
118
+ });
119
+ test('unmount preserves LDService.application', ()=>{
120
+ const { unmount } = subject();
121
+ unmount();
122
+ expect(providedLDService.application).toBe(otherApplication);
123
+ });
124
+ });
125
+ });
126
+ });
40
127
  });
41
128
 
42
129
  //# sourceMappingURL=ld-service-provider.test.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tests/ld-service-provider.test.tsx"],"sourcesContent":["import { Provider, useDependencies } from '@servicetitan/react-ioc';\nimport { render } from '@testing-library/react';\nimport { FC } from 'react';\n\nimport { getLDClient } from '../get-ld-client';\nimport { LDServiceProvider } from '../ld-service-provider';\nimport { LD_SERVICE_TOKEN, LDService } from '../types';\n\ndescribe(`[launchdarkly-service] ${LDServiceProvider.name}`, () => {\n let providedLDService: LDService;\n let singletons: Parameters<typeof Provider>[0]['singletons'];\n\n const Component: FC = () => {\n [providedLDService] = useDependencies(LD_SERVICE_TOKEN);\n return null;\n };\n\n beforeEach(() => (singletons = []));\n\n const subject = () => {\n return render(\n <Provider singletons={singletons}>\n <LDServiceProvider>\n <Component />\n </LDServiceProvider>\n </Provider>\n );\n };\n\n test('provides LDService instance', () => {\n subject();\n\n expect(providedLDService).toEqual({\n getClient: getLDClient,\n });\n });\n\n describe('when LDService is already provided', () => {\n const ldService = Symbol('ldService');\n\n beforeEach(() => singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: ldService }));\n\n test('provides existing LDService', () => {\n subject();\n\n expect(providedLDService).toBe(ldService);\n });\n });\n});\n"],"names":["Provider","useDependencies","render","getLDClient","LDServiceProvider","LD_SERVICE_TOKEN","describe","name","providedLDService","singletons","Component","beforeEach","subject","test","expect","toEqual","getClient","ldService","Symbol","push","provide","useValue","toBe"],"mappings":";AAAA,SAASA,QAAQ,EAAEC,eAAe,QAAQ,0BAA0B;AACpE,SAASC,MAAM,QAAQ,yBAAyB;AAGhD,SAASC,WAAW,QAAQ,mBAAmB;AAC/C,SAASC,iBAAiB,QAAQ,yBAAyB;AAC3D,SAASC,gBAAgB,QAAmB,WAAW;AAEvDC,SAAS,CAAC,uBAAuB,EAAEF,kBAAkBG,IAAI,EAAE,EAAE;IACzD,IAAIC;IACJ,IAAIC;IAEJ,MAAMC,YAAgB;QAClB,CAACF,kBAAkB,GAAGP,gBAAgBI;QACtC,OAAO;IACX;IAEAM,WAAW,IAAOF,aAAa,EAAE;IAEjC,MAAMG,UAAU;QACZ,OAAOV,qBACH,KAACF;YAASS,YAAYA;sBAClB,cAAA,KAACL;0BACG,cAAA,KAACM;;;IAIjB;IAEAG,KAAK,+BAA+B;QAChCD;QAEAE,OAAON,mBAAmBO,OAAO,CAAC;YAC9BC,WAAWb;QACf;IACJ;IAEAG,SAAS,sCAAsC;QAC3C,MAAMW,YAAYC,OAAO;QAEzBP,WAAW,IAAMF,uBAAAA,iCAAAA,WAAYU,IAAI,CAAC;gBAAEC,SAASf;gBAAkBgB,UAAUJ;YAAU;QAEnFJ,KAAK,+BAA+B;YAChCD;YAEAE,OAAON,mBAAmBc,IAAI,CAACL;QACnC;IACJ;AACJ"}
1
+ {"version":3,"sources":["../../src/tests/ld-service-provider.test.tsx"],"sourcesContent":["import { Provider, useDependencies } from '@servicetitan/react-ioc';\nimport { render } from '@testing-library/react';\nimport { ComponentProps, FC } from 'react';\nimport { getLDClient } from '../get-ld-client';\nimport { LDServiceProvider } from '../ld-service-provider';\nimport { LD_SERVICE_TOKEN, LDApplication, LDService } from '../types';\n\ndescribe(`[launchdarkly-service] ${LDServiceProvider.name}`, () => {\n let providedApplication: LDApplication | undefined;\n let providedLDService: LDService;\n let singletons: Parameters<typeof Provider>[0]['singletons'];\n let props: ComponentProps<typeof LDServiceProvider>;\n\n const Component: FC = () => {\n [providedLDService] = useDependencies(LD_SERVICE_TOKEN);\n providedApplication = providedLDService.application;\n return null;\n };\n\n beforeEach(() => {\n singletons = [];\n props = {};\n });\n\n const subject = () => {\n return render(\n <Provider singletons={singletons}>\n <LDServiceProvider {...props}>\n <Component />\n </LDServiceProvider>\n </Provider>\n );\n };\n\n test('provides LDService instance', () => {\n subject();\n\n expect(providedLDService).toEqual({ getClient: getLDClient });\n });\n\n test('provides no application', () => {\n subject();\n\n expect(providedApplication).toBeUndefined();\n });\n\n describe('when LDService is already provided', () => {\n const ldService: LDService = { getClient: jest.fn() };\n\n beforeEach(() => singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: ldService }));\n\n test('provides existing LDService', () => {\n subject();\n\n expect(providedLDService).toBe(ldService);\n });\n });\n\n describe('with \"application\" prop', () => {\n const application = { id: 'some-application', version: '1.0.0' };\n\n beforeEach(() => (props.application = application));\n\n function itProvidesApplication() {\n test('provides application', () => {\n subject();\n\n expect(providedApplication).toBe(application);\n });\n }\n\n itProvidesApplication();\n\n describe('when rerendered with new application', () => {\n const newApplication = { id: 'foo' };\n\n beforeEach(() => {\n const { rerender } = subject();\n\n rerender(\n <LDServiceProvider application={newApplication}>\n <Component />\n </LDServiceProvider>\n );\n });\n\n test('provides new application', () => {\n expect(providedApplication).toBe(newApplication);\n });\n });\n\n describe('when rerendered without application', () => {\n beforeEach(() => {\n const { rerender } = subject();\n\n rerender(\n <LDServiceProvider>\n <Component />\n </LDServiceProvider>\n );\n });\n\n test('drops application', () => {\n expect(providedApplication).toBeUndefined();\n });\n });\n\n describe('when LDService is already provided', () => {\n let providedLDService: LDService;\n\n beforeEach(() => {\n providedLDService = { getClient: jest.fn() };\n singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: providedLDService });\n });\n\n itProvidesApplication();\n\n test('unmount resets LDService.application', () => {\n const { unmount } = subject();\n unmount();\n\n expect(providedLDService.application).toBeUndefined();\n });\n\n describe('when provided LDService has application', () => {\n const otherApplication = { id: 'other-application', version: '2.0.0' };\n\n beforeEach(() => (providedLDService.application = otherApplication));\n\n test('provides inherited application', () => {\n subject();\n\n expect(providedApplication).toBe(otherApplication);\n });\n\n test('unmount preserves LDService.application', () => {\n const { unmount } = subject();\n unmount();\n\n expect(providedLDService.application).toBe(otherApplication);\n });\n });\n });\n });\n});\n"],"names":["Provider","useDependencies","render","getLDClient","LDServiceProvider","LD_SERVICE_TOKEN","describe","name","providedApplication","providedLDService","singletons","props","Component","application","beforeEach","subject","test","expect","toEqual","getClient","toBeUndefined","ldService","jest","fn","push","provide","useValue","toBe","id","version","itProvidesApplication","newApplication","rerender","unmount","otherApplication"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tests/with-feature-flag.test.tsx"],"sourcesContent":["import '@testing-library/jest-dom';\nimport { render, screen } from '@testing-library/react';\nimport { LDFlagValue, useFlags } from 'launchdarkly-react-client-sdk';\n\nimport { WithFeatureFlag } from '../with-feature-flag';\n\njest.mock('launchdarkly-react-client-sdk', () => ({\n useFlags: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${WithFeatureFlag.name}`, () => {\n const flagKey = 'foo';\n const childContent = 'Flag is ON';\n let props: Parameters<typeof WithFeatureFlag>[0];\n let flagValue: LDFlagValue;\n\n beforeEach(() => {\n props = { flagKey, children: childContent };\n jest.mocked(useFlags).mockImplementation(() => ({ [flagKey]: flagValue }));\n });\n\n const subject = () => render(<WithFeatureFlag {...props} />);\n\n function itRendersNothing() {\n test('renders nothing', () => {\n subject();\n\n expect(screen.queryByText(childContent)).not.toBeInTheDocument();\n });\n }\n\n function itRendersChildren() {\n test('renders children', () => {\n subject();\n\n expect(screen.getByText(childContent)).toBeInTheDocument();\n });\n }\n\n itRendersNothing();\n\n describe('when flag is turned on', () => {\n beforeEach(() => (flagValue = true));\n\n itRendersChildren();\n\n describe('with on prop', () => {\n const onContent = 'Flag is ENABLED';\n\n beforeEach(() => (props.on = () => onContent));\n\n test('renders on content', () => {\n subject();\n\n expect(screen.getByText(onContent)).toBeInTheDocument();\n });\n });\n });\n\n describe('when flag is turned off', () => {\n beforeEach(() => (flagValue = false));\n\n itRendersNothing();\n\n describe('with off prop', () => {\n const offContent = 'flag is OFF';\n\n beforeEach(() => (props.off = () => offContent));\n\n test('renders off content', () => {\n subject();\n\n expect(screen.getByText(offContent)).toBeInTheDocument();\n });\n });\n });\n\n describe('with flag value', () => {\n beforeEach(() => (props.value = 'bar'));\n\n itRendersNothing();\n\n describe('when flag matches value', () => {\n beforeEach(() => (flagValue = props.value));\n\n itRendersChildren();\n });\n });\n});\n"],"names":["render","screen","useFlags","WithFeatureFlag","jest","mock","fn","describe","name","flagKey","childContent","props","flagValue","beforeEach","children","mocked","mockImplementation","subject","itRendersNothing","test","expect","queryByText","not","toBeInTheDocument","itRendersChildren","getByText","onContent","on","offContent","off","value"],"mappings":";AAAA,OAAO,4BAA4B;AACnC,SAASA,MAAM,EAAEC,MAAM,QAAQ,yBAAyB;AACxD,SAAsBC,QAAQ,QAAQ,gCAAgC;AAEtE,SAASC,eAAe,QAAQ,uBAAuB;AAEvDC,KAAKC,IAAI,CAAC,iCAAiC,IAAO,CAAA;QAC9CH,UAAUE,KAAKE,EAAE;IACrB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEJ,gBAAgBK,IAAI,EAAE,EAAE;IACvD,MAAMC,UAAU;IAChB,MAAMC,eAAe;IACrB,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACPF,QAAQ;YAAEF;YAASK,UAAUJ;QAAa;QAC1CN,KAAKW,MAAM,CAACb,UAAUc,kBAAkB,CAAC,IAAO,CAAA;gBAAE,CAACP,QAAQ,EAAEG;YAAU,CAAA;IAC3E;IAEA,MAAMK,UAAU,IAAMjB,qBAAO,KAACG;YAAiB,GAAGQ,KAAK;;IAEvD,SAASO;QACLC,KAAK,mBAAmB;YACpBF;YAEAG,OAAOnB,OAAOoB,WAAW,CAACX,eAAeY,GAAG,CAACC,iBAAiB;QAClE;IACJ;IAEA,SAASC;QACLL,KAAK,oBAAoB;YACrBF;YAEAG,OAAOnB,OAAOwB,SAAS,CAACf,eAAea,iBAAiB;QAC5D;IACJ;IAEAL;IAEAX,SAAS,0BAA0B;QAC/BM,WAAW,IAAOD,YAAY;QAE9BY;QAEAjB,SAAS,gBAAgB;YACrB,MAAMmB,YAAY;YAElBb,WAAW,IAAOF,MAAMgB,EAAE,GAAG,IAAMD;YAEnCP,KAAK,sBAAsB;gBACvBF;gBAEAG,OAAOnB,OAAOwB,SAAS,CAACC,YAAYH,iBAAiB;YACzD;QACJ;IACJ;IAEAhB,SAAS,2BAA2B;QAChCM,WAAW,IAAOD,YAAY;QAE9BM;QAEAX,SAAS,iBAAiB;YACtB,MAAMqB,aAAa;YAEnBf,WAAW,IAAOF,MAAMkB,GAAG,GAAG,IAAMD;YAEpCT,KAAK,uBAAuB;gBACxBF;gBAEAG,OAAOnB,OAAOwB,SAAS,CAACG,aAAaL,iBAAiB;YAC1D;QACJ;IACJ;IAEAhB,SAAS,mBAAmB;QACxBM,WAAW,IAAOF,MAAMmB,KAAK,GAAG;QAEhCZ;QAEAX,SAAS,2BAA2B;YAChCM,WAAW,IAAOD,YAAYD,MAAMmB,KAAK;YAEzCN;QACJ;IACJ;AACJ"}
1
+ {"version":3,"sources":["../../src/tests/with-feature-flag.test.tsx"],"sourcesContent":["import '@testing-library/jest-dom';\nimport { render, screen } from '@testing-library/react';\nimport { LDFlagValue, useFlags } from 'launchdarkly-react-client-sdk';\nimport { WithFeatureFlag } from '../with-feature-flag';\n\njest.mock('launchdarkly-react-client-sdk', () => ({\n useFlags: jest.fn(),\n}));\n\ndescribe(`[launchdarkly-service] ${WithFeatureFlag.name}`, () => {\n const flagKey = 'foo';\n const childContent = 'Flag is ON';\n let props: Parameters<typeof WithFeatureFlag>[0];\n let flagValue: LDFlagValue;\n\n beforeEach(() => {\n props = { flagKey, children: childContent };\n jest.mocked(useFlags).mockImplementation(() => ({ [flagKey]: flagValue }));\n });\n\n const subject = () => render(<WithFeatureFlag {...props} />);\n\n function itRendersNothing() {\n test('renders nothing', () => {\n subject();\n\n expect(screen.queryByText(childContent)).not.toBeInTheDocument();\n });\n }\n\n function itRendersChildren() {\n test('renders children', () => {\n subject();\n\n expect(screen.getByText(childContent)).toBeInTheDocument();\n });\n }\n\n itRendersNothing();\n\n describe('when flag is turned on', () => {\n beforeEach(() => (flagValue = true));\n\n itRendersChildren();\n\n describe('with on prop', () => {\n const onContent = 'Flag is ENABLED';\n\n beforeEach(() => (props.on = () => onContent));\n\n test('renders on content', () => {\n subject();\n\n expect(screen.getByText(onContent)).toBeInTheDocument();\n });\n });\n });\n\n describe('when flag is turned off', () => {\n beforeEach(() => (flagValue = false));\n\n itRendersNothing();\n\n describe('with off prop', () => {\n const offContent = 'flag is OFF';\n\n beforeEach(() => (props.off = () => offContent));\n\n test('renders off content', () => {\n subject();\n\n expect(screen.getByText(offContent)).toBeInTheDocument();\n });\n });\n });\n\n describe('with flag value', () => {\n beforeEach(() => (props.value = 'bar'));\n\n itRendersNothing();\n\n describe('when flag matches value', () => {\n beforeEach(() => (flagValue = props.value));\n\n itRendersChildren();\n });\n });\n});\n"],"names":["render","screen","useFlags","WithFeatureFlag","jest","mock","fn","describe","name","flagKey","childContent","props","flagValue","beforeEach","children","mocked","mockImplementation","subject","itRendersNothing","test","expect","queryByText","not","toBeInTheDocument","itRendersChildren","getByText","onContent","on","offContent","off","value"],"mappings":";AAAA,OAAO,4BAA4B;AACnC,SAASA,MAAM,EAAEC,MAAM,QAAQ,yBAAyB;AACxD,SAAsBC,QAAQ,QAAQ,gCAAgC;AACtE,SAASC,eAAe,QAAQ,uBAAuB;AAEvDC,KAAKC,IAAI,CAAC,iCAAiC,IAAO,CAAA;QAC9CH,UAAUE,KAAKE,EAAE;IACrB,CAAA;AAEAC,SAAS,CAAC,uBAAuB,EAAEJ,gBAAgBK,IAAI,EAAE,EAAE;IACvD,MAAMC,UAAU;IAChB,MAAMC,eAAe;IACrB,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACPF,QAAQ;YAAEF;YAASK,UAAUJ;QAAa;QAC1CN,KAAKW,MAAM,CAACb,UAAUc,kBAAkB,CAAC,IAAO,CAAA;gBAAE,CAACP,QAAQ,EAAEG;YAAU,CAAA;IAC3E;IAEA,MAAMK,UAAU,IAAMjB,qBAAO,KAACG;YAAiB,GAAGQ,KAAK;;IAEvD,SAASO;QACLC,KAAK,mBAAmB;YACpBF;YAEAG,OAAOnB,OAAOoB,WAAW,CAACX,eAAeY,GAAG,CAACC,iBAAiB;QAClE;IACJ;IAEA,SAASC;QACLL,KAAK,oBAAoB;YACrBF;YAEAG,OAAOnB,OAAOwB,SAAS,CAACf,eAAea,iBAAiB;QAC5D;IACJ;IAEAL;IAEAX,SAAS,0BAA0B;QAC/BM,WAAW,IAAOD,YAAY;QAE9BY;QAEAjB,SAAS,gBAAgB;YACrB,MAAMmB,YAAY;YAElBb,WAAW,IAAOF,MAAMgB,EAAE,GAAG,IAAMD;YAEnCP,KAAK,sBAAsB;gBACvBF;gBAEAG,OAAOnB,OAAOwB,SAAS,CAACC,YAAYH,iBAAiB;YACzD;QACJ;IACJ;IAEAhB,SAAS,2BAA2B;QAChCM,WAAW,IAAOD,YAAY;QAE9BM;QAEAX,SAAS,iBAAiB;YACtB,MAAMqB,aAAa;YAEnBf,WAAW,IAAOF,MAAMkB,GAAG,GAAG,IAAMD;YAEpCT,KAAK,uBAAuB;gBACxBF;gBAEAG,OAAOnB,OAAOwB,SAAS,CAACG,aAAaL,iBAAiB;YAC1D;QACJ;IACJ;IAEAhB,SAAS,mBAAmB;QACxBM,WAAW,IAAOF,MAAMmB,KAAK,GAAG;QAEhCZ;QAEAX,SAAS,2BAA2B;YAChCM,WAAW,IAAOD,YAAYD,MAAMmB,KAAK;YAEzCN;QACJ;IACJ;AACJ"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { type LDContext, type LDClient, type LDOptions } from 'launchdarkly-js-client-sdk';
1
+ import type { LDClient, LDContext, LDOptions } from 'launchdarkly-js-client-sdk';
2
2
  export declare const LD_SERVICE_TOKEN: import("@servicetitan/react-ioc").SymbolToken<LDService>;
3
+ export type LDApplication = LDOptions['application'];
3
4
  export interface ClientConfig {
4
5
  clientSideID: string;
5
6
  context?: LDContext;
@@ -7,6 +8,7 @@ export interface ClientConfig {
7
8
  }
8
9
  export interface LDService {
9
10
  getClient: (config: ClientConfig) => LDClient;
11
+ application?: LDApplication;
10
12
  }
11
13
  export type FlagKey<S, K extends keyof S> = K & {
12
14
  typeRef?: S[K];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE3F,eAAO,MAAM,gBAAgB,0DAA6C,CAAC;AAE3E,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACtB,SAAS,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,QAAQ,CAAC;CACjD;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG;IAC5C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;CAClB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEjF,eAAO,MAAM,gBAAgB,0DAA6C,CAAC;AAE3E,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;AAErD,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACtB,SAAS,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,QAAQ,CAAC;IAC9C,WAAW,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG;IAC5C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;CAClB,CAAC"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import { symbolToken } from '@servicetitan/react-ioc';\nimport { type LDContext, type LDClient, type LDOptions } from 'launchdarkly-js-client-sdk';\n\nexport const LD_SERVICE_TOKEN = symbolToken<LDService>('LD_SERVICE_TOKEN');\n\nexport interface ClientConfig {\n clientSideID: string;\n context?: LDContext;\n options?: LDOptions;\n}\n\nexport interface LDService {\n getClient: (config: ClientConfig) => LDClient;\n}\n\nexport type FlagKey<S, K extends keyof S> = K & {\n typeRef?: S[K];\n};\n"],"names":["symbolToken","LD_SERVICE_TOKEN"],"mappings":"AAAA,SAASA,WAAW,QAAQ,0BAA0B;AAGtD,OAAO,MAAMC,mBAAmBD,YAAuB,oBAAoB"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import { symbolToken } from '@servicetitan/react-ioc';\nimport type { LDClient, LDContext, LDOptions } from 'launchdarkly-js-client-sdk';\n\nexport const LD_SERVICE_TOKEN = symbolToken<LDService>('LD_SERVICE_TOKEN');\n\nexport type LDApplication = LDOptions['application'];\n\nexport interface ClientConfig {\n clientSideID: string;\n context?: LDContext;\n options?: LDOptions;\n}\n\nexport interface LDService {\n getClient: (config: ClientConfig) => LDClient;\n application?: LDApplication;\n}\n\nexport type FlagKey<S, K extends keyof S> = K & {\n typeRef?: S[K];\n};\n"],"names":["symbolToken","LD_SERVICE_TOKEN"],"mappings":"AAAA,SAASA,WAAW,QAAQ,0BAA0B;AAGtD,OAAO,MAAMC,mBAAmBD,YAAuB,oBAAoB"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@servicetitan/launchdarkly-service",
3
- "version": "33.1.0",
4
- "description": "",
5
- "homepage": "https://docs.st.dev/docs/frontend/launchdarkly-service",
3
+ "version": "34.0.0",
4
+ "description": "Service for creating and reusing client connections for LaunchDarkly",
5
+ "homepage": "https://docs.st.dev/docs/frontend/uikit/launchdarkly-service",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/servicetitan/uikit.git",
@@ -16,19 +16,19 @@
16
16
  "src"
17
17
  ],
18
18
  "devDependencies": {
19
- "@servicetitan/log-service": "33.1.0",
20
- "@servicetitan/react-ioc": "33.1.0",
19
+ "@servicetitan/log-service": "34.0.0",
20
+ "@servicetitan/react-ioc": "34.0.0",
21
21
  "@testing-library/dom": "^10.4.1",
22
22
  "@testing-library/jest-dom": "^6.9.1",
23
- "@testing-library/react": "^16.3.0",
23
+ "@testing-library/react": "^16.3.2",
24
24
  "launchdarkly-js-client-sdk": "3.5.0",
25
25
  "launchdarkly-react-client-sdk": "3.6.1",
26
26
  "mobx": "~6.13.7",
27
27
  "react": "~18.3.1"
28
28
  },
29
29
  "peerDependencies": {
30
- "@servicetitan/log-service": "33.1.0",
31
- "@servicetitan/react-ioc": "33.1.0",
30
+ "@servicetitan/log-service": "34.0.0",
31
+ "@servicetitan/react-ioc": "34.0.0",
32
32
  "launchdarkly-js-client-sdk": "3.5.0",
33
33
  "launchdarkly-react-client-sdk": "3.6.1",
34
34
  "mobx": ">= 6.13.7",
@@ -40,5 +40,5 @@
40
40
  "cli": {
41
41
  "webpack": false
42
42
  },
43
- "gitHead": "126948560bcb684f276373beb7ce45faac94205c"
43
+ "gitHead": "e193dc22703963f67099874a24de535d0696b6e2"
44
44
  }
@@ -1,7 +1,6 @@
1
1
  import { useDependencies } from '@servicetitan/react-ioc';
2
2
  import { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';
3
3
  import { PropsWithChildren, useEffect, useState } from 'react';
4
-
5
4
  import { FeatureFlagStore } from './feature-flag-store';
6
5
 
7
6
  export function FeatureFlagProvider({ children }: PropsWithChildren) {
@@ -6,7 +6,6 @@ import {
6
6
  ProviderConfig as BaseProviderConfig,
7
7
  } from 'launchdarkly-react-client-sdk';
8
8
  import { FC, PropsWithChildren, useEffect, useReducer, useState } from 'react';
9
-
10
9
  import { FeatureFlagProvider } from './feature-flag-provider';
11
10
  import { FeatureFlagStore } from './feature-flag-store';
12
11
  import { getLDClient } from './get-ld-client';
@@ -27,7 +26,10 @@ export const LDProvider: FC<PropsWithChildren<ProviderConfig>> = provide({
27
26
 
28
27
  useEffect(() => {
29
28
  (async function initializeClient() {
30
- const config = { clientSideID, context };
29
+ const options = ldService?.application
30
+ ? { application: ldService.application }
31
+ : undefined;
32
+ const config: BaseProviderConfig = { clientSideID, context, options };
31
33
  const client = ldService?.getClient(config) ?? getLDClient(config);
32
34
  if (waitForInitialization) {
33
35
  try {
@@ -1,12 +1,32 @@
1
- import { provide } from '@servicetitan/react-ioc';
2
-
1
+ import { provide, useDependencies } from '@servicetitan/react-ioc';
2
+ import { FC, PropsWithChildren, useEffect, useRef } from 'react';
3
3
  import { getLDClient } from './get-ld-client';
4
- import { LD_SERVICE_TOKEN, LDService } from './types';
4
+ import { LD_SERVICE_TOKEN, LDApplication, LDService } from './types';
5
5
 
6
6
  const ldService: LDService = {
7
7
  getClient: getLDClient,
8
8
  };
9
9
 
10
- export const LDServiceProvider = provide({
10
+ interface LDServiceProviderProps {
11
+ application?: LDApplication;
12
+ }
13
+
14
+ export const LDServiceProvider: FC<PropsWithChildren<LDServiceProviderProps>> = provide({
11
15
  singletons: [{ provide: LD_SERVICE_TOKEN, useValue: ldService, inherit: true }],
12
- })(({ children }) => children);
16
+ })(({ children, application }) => {
17
+ const [providedLDService] = useDependencies(LD_SERVICE_TOKEN);
18
+ const prevApplication = useRef(providedLDService.application);
19
+
20
+ if (providedLDService === ldService || !providedLDService.application) {
21
+ providedLDService.application = application;
22
+ }
23
+
24
+ useEffect(() => {
25
+ return () => {
26
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27
+ providedLDService.application = prevApplication.current;
28
+ };
29
+ }, [providedLDService]);
30
+
31
+ return children;
32
+ });
@@ -1,11 +1,10 @@
1
- import '@testing-library/jest-dom';
2
1
  import { Provider } from '@servicetitan/react-ioc';
3
- import { FC } from 'react';
2
+ import '@testing-library/jest-dom';
4
3
  import { render, screen } from '@testing-library/react';
5
-
4
+ import { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';
5
+ import { FC } from 'react';
6
6
  import { FeatureFlagProvider } from '../feature-flag-provider';
7
7
  import { FeatureFlagStore } from '../feature-flag-store';
8
- import { useFlags, useLDClient } from 'launchdarkly-react-client-sdk';
9
8
 
10
9
  jest.mock('launchdarkly-react-client-sdk', () => ({
11
10
  useLDClient: jest.fn(),
@@ -1,5 +1,4 @@
1
1
  import { initialize } from 'launchdarkly-js-client-sdk';
2
-
3
2
  import { getLDClient } from '../get-ld-client';
4
3
 
5
4
  jest.mock('launchdarkly-js-client-sdk', () => ({
@@ -1,10 +1,9 @@
1
- import '@testing-library/jest-dom';
2
1
  import { Log } from '@servicetitan/log-service';
3
2
  import { Provider, useDependencies } from '@servicetitan/react-ioc';
3
+ import '@testing-library/jest-dom';
4
4
  import { render, screen, waitFor } from '@testing-library/react';
5
5
  import { LDClient } from 'launchdarkly-js-client-sdk';
6
6
  import { act, FC, Fragment } from 'react';
7
-
8
7
  import { FeatureFlagStore } from '../feature-flag-store';
9
8
  import { getLDClient } from '../get-ld-client';
10
9
  import { LDProvider } from '../ld-provider';
@@ -182,11 +181,10 @@ describe(`[launchdarkly-service] ${LDProvider.name}`, () => {
182
181
  waitForInitialization: jest.fn().mockResolvedValue(undefined),
183
182
  toString: () => 'ldServiceClient',
184
183
  };
185
- const ldService: LDService = {
186
- getClient: jest.fn().mockReturnValue(ldServiceClient),
187
- };
184
+ let ldService: LDService;
188
185
 
189
186
  beforeEach(() => {
187
+ ldService = { getClient: jest.fn().mockReturnValue(ldServiceClient) };
190
188
  singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: ldService });
191
189
  });
192
190
 
@@ -199,5 +197,23 @@ describe(`[launchdarkly-service] ${LDProvider.name}`, () => {
199
197
 
200
198
  expect(ldServiceClient.waitForInitialization).toHaveBeenCalled();
201
199
  });
200
+
201
+ describe('when application is provided', () => {
202
+ const application = { id: 'some-application', version: '1.2.3' };
203
+
204
+ beforeEach(() => (ldService.application = application));
205
+
206
+ test('passes application to LDClient', async () => {
207
+ subject();
208
+
209
+ await waitFor(() => expectLDProvider());
210
+
211
+ expect(ldService.getClient).toHaveBeenCalledWith(
212
+ expect.objectContaining({
213
+ options: { application },
214
+ })
215
+ );
216
+ });
217
+ });
202
218
  });
203
219
  });
@@ -1,26 +1,31 @@
1
1
  import { Provider, useDependencies } from '@servicetitan/react-ioc';
2
2
  import { render } from '@testing-library/react';
3
- import { FC } from 'react';
4
-
3
+ import { ComponentProps, FC } from 'react';
5
4
  import { getLDClient } from '../get-ld-client';
6
5
  import { LDServiceProvider } from '../ld-service-provider';
7
- import { LD_SERVICE_TOKEN, LDService } from '../types';
6
+ import { LD_SERVICE_TOKEN, LDApplication, LDService } from '../types';
8
7
 
9
8
  describe(`[launchdarkly-service] ${LDServiceProvider.name}`, () => {
9
+ let providedApplication: LDApplication | undefined;
10
10
  let providedLDService: LDService;
11
11
  let singletons: Parameters<typeof Provider>[0]['singletons'];
12
+ let props: ComponentProps<typeof LDServiceProvider>;
12
13
 
13
14
  const Component: FC = () => {
14
15
  [providedLDService] = useDependencies(LD_SERVICE_TOKEN);
16
+ providedApplication = providedLDService.application;
15
17
  return null;
16
18
  };
17
19
 
18
- beforeEach(() => (singletons = []));
20
+ beforeEach(() => {
21
+ singletons = [];
22
+ props = {};
23
+ });
19
24
 
20
25
  const subject = () => {
21
26
  return render(
22
27
  <Provider singletons={singletons}>
23
- <LDServiceProvider>
28
+ <LDServiceProvider {...props}>
24
29
  <Component />
25
30
  </LDServiceProvider>
26
31
  </Provider>
@@ -30,13 +35,17 @@ describe(`[launchdarkly-service] ${LDServiceProvider.name}`, () => {
30
35
  test('provides LDService instance', () => {
31
36
  subject();
32
37
 
33
- expect(providedLDService).toEqual({
34
- getClient: getLDClient,
35
- });
38
+ expect(providedLDService).toEqual({ getClient: getLDClient });
39
+ });
40
+
41
+ test('provides no application', () => {
42
+ subject();
43
+
44
+ expect(providedApplication).toBeUndefined();
36
45
  });
37
46
 
38
47
  describe('when LDService is already provided', () => {
39
- const ldService = Symbol('ldService');
48
+ const ldService: LDService = { getClient: jest.fn() };
40
49
 
41
50
  beforeEach(() => singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: ldService }));
42
51
 
@@ -46,4 +55,91 @@ describe(`[launchdarkly-service] ${LDServiceProvider.name}`, () => {
46
55
  expect(providedLDService).toBe(ldService);
47
56
  });
48
57
  });
58
+
59
+ describe('with "application" prop', () => {
60
+ const application = { id: 'some-application', version: '1.0.0' };
61
+
62
+ beforeEach(() => (props.application = application));
63
+
64
+ function itProvidesApplication() {
65
+ test('provides application', () => {
66
+ subject();
67
+
68
+ expect(providedApplication).toBe(application);
69
+ });
70
+ }
71
+
72
+ itProvidesApplication();
73
+
74
+ describe('when rerendered with new application', () => {
75
+ const newApplication = { id: 'foo' };
76
+
77
+ beforeEach(() => {
78
+ const { rerender } = subject();
79
+
80
+ rerender(
81
+ <LDServiceProvider application={newApplication}>
82
+ <Component />
83
+ </LDServiceProvider>
84
+ );
85
+ });
86
+
87
+ test('provides new application', () => {
88
+ expect(providedApplication).toBe(newApplication);
89
+ });
90
+ });
91
+
92
+ describe('when rerendered without application', () => {
93
+ beforeEach(() => {
94
+ const { rerender } = subject();
95
+
96
+ rerender(
97
+ <LDServiceProvider>
98
+ <Component />
99
+ </LDServiceProvider>
100
+ );
101
+ });
102
+
103
+ test('drops application', () => {
104
+ expect(providedApplication).toBeUndefined();
105
+ });
106
+ });
107
+
108
+ describe('when LDService is already provided', () => {
109
+ let providedLDService: LDService;
110
+
111
+ beforeEach(() => {
112
+ providedLDService = { getClient: jest.fn() };
113
+ singletons?.push({ provide: LD_SERVICE_TOKEN, useValue: providedLDService });
114
+ });
115
+
116
+ itProvidesApplication();
117
+
118
+ test('unmount resets LDService.application', () => {
119
+ const { unmount } = subject();
120
+ unmount();
121
+
122
+ expect(providedLDService.application).toBeUndefined();
123
+ });
124
+
125
+ describe('when provided LDService has application', () => {
126
+ const otherApplication = { id: 'other-application', version: '2.0.0' };
127
+
128
+ beforeEach(() => (providedLDService.application = otherApplication));
129
+
130
+ test('provides inherited application', () => {
131
+ subject();
132
+
133
+ expect(providedApplication).toBe(otherApplication);
134
+ });
135
+
136
+ test('unmount preserves LDService.application', () => {
137
+ const { unmount } = subject();
138
+ unmount();
139
+
140
+ expect(providedLDService.application).toBe(otherApplication);
141
+ });
142
+ });
143
+ });
144
+ });
49
145
  });
@@ -1,7 +1,6 @@
1
1
  import '@testing-library/jest-dom';
2
2
  import { render, screen } from '@testing-library/react';
3
3
  import { LDFlagValue, useFlags } from 'launchdarkly-react-client-sdk';
4
-
5
4
  import { WithFeatureFlag } from '../with-feature-flag';
6
5
 
7
6
  jest.mock('launchdarkly-react-client-sdk', () => ({
package/src/types.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { symbolToken } from '@servicetitan/react-ioc';
2
- import { type LDContext, type LDClient, type LDOptions } from 'launchdarkly-js-client-sdk';
2
+ import type { LDClient, LDContext, LDOptions } from 'launchdarkly-js-client-sdk';
3
3
 
4
4
  export const LD_SERVICE_TOKEN = symbolToken<LDService>('LD_SERVICE_TOKEN');
5
5
 
6
+ export type LDApplication = LDOptions['application'];
7
+
6
8
  export interface ClientConfig {
7
9
  clientSideID: string;
8
10
  context?: LDContext;
@@ -11,6 +13,7 @@ export interface ClientConfig {
11
13
 
12
14
  export interface LDService {
13
15
  getClient: (config: ClientConfig) => LDClient;
16
+ application?: LDApplication;
14
17
  }
15
18
 
16
19
  export type FlagKey<S, K extends keyof S> = K & {