@schematichq/schematic-react 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schematic-react.cjs.js +110 -36
- package/dist/schematic-react.esm.js +111 -37
- package/package.json +2 -2
@@ -667,37 +667,89 @@ var Schematic = class {
|
|
667
667
|
});
|
668
668
|
}
|
669
669
|
}
|
670
|
-
|
671
|
-
|
670
|
+
/**
|
671
|
+
* Get value for a single flag.
|
672
|
+
* In WebSocket mode, returns cached values if connection is active, otherwise establishes
|
673
|
+
* new connection and then returns the requestedvalue. Falls back to REST API if WebSocket
|
674
|
+
* connection fails.
|
675
|
+
* In REST mode, makes an API call for each check.
|
676
|
+
*/
|
672
677
|
async checkFlag(options) {
|
673
678
|
const { fallback = false, key } = options;
|
674
679
|
const context = options.context || this.context;
|
675
|
-
|
676
|
-
|
680
|
+
const contextStr = contextString(context);
|
681
|
+
if (!this.useWebSocket) {
|
682
|
+
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
683
|
+
return fetch(requestUrl, {
|
684
|
+
method: "POST",
|
685
|
+
headers: {
|
686
|
+
...this.additionalHeaders ?? {},
|
687
|
+
"Content-Type": "application/json;charset=UTF-8",
|
688
|
+
"X-Schematic-Api-Key": this.apiKey
|
689
|
+
},
|
690
|
+
body: JSON.stringify(context)
|
691
|
+
}).then((response) => {
|
692
|
+
if (!response.ok) {
|
693
|
+
throw new Error("Network response was not ok");
|
694
|
+
}
|
695
|
+
return response.json();
|
696
|
+
}).then((data) => {
|
697
|
+
return data.data.value;
|
698
|
+
}).catch((error) => {
|
699
|
+
console.error("There was a problem with the fetch operation:", error);
|
700
|
+
return fallback;
|
701
|
+
});
|
702
|
+
}
|
703
|
+
try {
|
704
|
+
const existingVals = this.values[contextStr];
|
705
|
+
if (this.conn && typeof existingVals !== "undefined" && typeof existingVals[key] !== "undefined") {
|
706
|
+
return existingVals[key];
|
707
|
+
}
|
708
|
+
try {
|
709
|
+
await this.setContext(context);
|
710
|
+
} catch (error) {
|
711
|
+
console.error(
|
712
|
+
"WebSocket connection failed, falling back to REST:",
|
713
|
+
error
|
714
|
+
);
|
715
|
+
return this.fallbackToRest(key, context, fallback);
|
716
|
+
}
|
717
|
+
const contextVals = this.values[contextStr] ?? {};
|
677
718
|
return typeof contextVals[key] === "undefined" ? fallback : contextVals[key];
|
719
|
+
} catch (error) {
|
720
|
+
console.error("Unexpected error in checkFlag:", error);
|
721
|
+
return fallback;
|
678
722
|
}
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
723
|
+
}
|
724
|
+
/**
|
725
|
+
* Helper method for falling back to REST API when WebSocket connection fails
|
726
|
+
*/
|
727
|
+
async fallbackToRest(key, context, fallback) {
|
728
|
+
try {
|
729
|
+
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
730
|
+
const response = await fetch(requestUrl, {
|
731
|
+
method: "POST",
|
732
|
+
headers: {
|
733
|
+
...this.additionalHeaders ?? {},
|
734
|
+
"Content-Type": "application/json;charset=UTF-8",
|
735
|
+
"X-Schematic-Api-Key": this.apiKey
|
736
|
+
},
|
737
|
+
body: JSON.stringify(context)
|
738
|
+
});
|
689
739
|
if (!response.ok) {
|
690
740
|
throw new Error("Network response was not ok");
|
691
741
|
}
|
692
|
-
|
693
|
-
}).then((data) => {
|
742
|
+
const data = await response.json();
|
694
743
|
return data.data.value;
|
695
|
-
}
|
696
|
-
console.error("
|
744
|
+
} catch (error) {
|
745
|
+
console.error("REST API call failed, using fallback value:", error);
|
697
746
|
return fallback;
|
698
|
-
}
|
747
|
+
}
|
699
748
|
}
|
700
|
-
|
749
|
+
/**
|
750
|
+
* Make an API call to fetch all flag values for a given context.
|
751
|
+
* Recommended for use in REST mode only.
|
752
|
+
*/
|
701
753
|
checkFlags = async (context) => {
|
702
754
|
context = context || this.context;
|
703
755
|
const requestUrl = `${this.apiUrl}/flags/check`;
|
@@ -728,18 +780,30 @@ var Schematic = class {
|
|
728
780
|
return false;
|
729
781
|
});
|
730
782
|
};
|
731
|
-
|
783
|
+
/**
|
784
|
+
* Send an identify event.
|
785
|
+
* This will set the context for subsequent flag evaluation and events, and will also
|
786
|
+
* send an identify event to the Schematic API which will upsert a user and company.
|
787
|
+
*/
|
732
788
|
identify = (body) => {
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
789
|
+
try {
|
790
|
+
this.setContext({
|
791
|
+
company: body.company?.keys,
|
792
|
+
user: body.keys
|
793
|
+
});
|
794
|
+
} catch (error) {
|
795
|
+
console.error("Error setting context:", error);
|
796
|
+
}
|
737
797
|
return this.handleEvent("identify", body);
|
738
798
|
};
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
799
|
+
/**
|
800
|
+
* Set the flag evaluation context.
|
801
|
+
* In WebSocket mode, this will:
|
802
|
+
* 1. Open a websocket connection if not already open
|
803
|
+
* 2. Send the context to the server
|
804
|
+
* 3. Wait for initial flag values to be returned
|
805
|
+
* The promise resolves when initial flag values are received.
|
806
|
+
*/
|
743
807
|
setContext = async (context) => {
|
744
808
|
if (!this.useWebSocket) {
|
745
809
|
this.context = context;
|
@@ -753,10 +817,14 @@ var Schematic = class {
|
|
753
817
|
const socket = await this.conn;
|
754
818
|
await this.wsSendMessage(socket, context);
|
755
819
|
} catch (error) {
|
756
|
-
console.error("
|
820
|
+
console.error("Failed to establish WebSocket connection:", error);
|
821
|
+
throw error;
|
757
822
|
}
|
758
823
|
};
|
759
|
-
|
824
|
+
/**
|
825
|
+
* Send a track event
|
826
|
+
* Track usage for a company and/or user.
|
827
|
+
*/
|
760
828
|
track = (body) => {
|
761
829
|
const { company, user, event, traits } = body;
|
762
830
|
return this.handleEvent("track", {
|
@@ -828,6 +896,9 @@ var Schematic = class {
|
|
828
896
|
/**
|
829
897
|
* Websocket management
|
830
898
|
*/
|
899
|
+
/**
|
900
|
+
* If using websocket mode, close the connection when done.
|
901
|
+
*/
|
831
902
|
cleanup = async () => {
|
832
903
|
if (this.conn) {
|
833
904
|
try {
|
@@ -965,16 +1036,19 @@ var SchematicProvider = ({
|
|
965
1036
|
publishableKey,
|
966
1037
|
...clientOpts
|
967
1038
|
}) => {
|
1039
|
+
const initialOptsRef = (0, import_react.useRef)({
|
1040
|
+
publishableKey,
|
1041
|
+
useWebSocket: clientOpts.useWebSocket ?? true,
|
1042
|
+
...clientOpts
|
1043
|
+
});
|
968
1044
|
const client = (0, import_react.useMemo)(() => {
|
969
|
-
const { useWebSocket = true } = clientOpts;
|
970
1045
|
if (providedClient) {
|
971
1046
|
return providedClient;
|
972
1047
|
}
|
973
|
-
return new Schematic(publishableKey, {
|
974
|
-
|
975
|
-
...clientOpts
|
1048
|
+
return new Schematic(initialOptsRef.current.publishableKey, {
|
1049
|
+
...initialOptsRef.current
|
976
1050
|
});
|
977
|
-
}, [providedClient
|
1051
|
+
}, [providedClient]);
|
978
1052
|
(0, import_react.useEffect)(() => {
|
979
1053
|
return () => {
|
980
1054
|
if (!providedClient) {
|
@@ -625,37 +625,89 @@ var Schematic = class {
|
|
625
625
|
});
|
626
626
|
}
|
627
627
|
}
|
628
|
-
|
629
|
-
|
628
|
+
/**
|
629
|
+
* Get value for a single flag.
|
630
|
+
* In WebSocket mode, returns cached values if connection is active, otherwise establishes
|
631
|
+
* new connection and then returns the requestedvalue. Falls back to REST API if WebSocket
|
632
|
+
* connection fails.
|
633
|
+
* In REST mode, makes an API call for each check.
|
634
|
+
*/
|
630
635
|
async checkFlag(options) {
|
631
636
|
const { fallback = false, key } = options;
|
632
637
|
const context = options.context || this.context;
|
633
|
-
|
634
|
-
|
638
|
+
const contextStr = contextString(context);
|
639
|
+
if (!this.useWebSocket) {
|
640
|
+
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
641
|
+
return fetch(requestUrl, {
|
642
|
+
method: "POST",
|
643
|
+
headers: {
|
644
|
+
...this.additionalHeaders ?? {},
|
645
|
+
"Content-Type": "application/json;charset=UTF-8",
|
646
|
+
"X-Schematic-Api-Key": this.apiKey
|
647
|
+
},
|
648
|
+
body: JSON.stringify(context)
|
649
|
+
}).then((response) => {
|
650
|
+
if (!response.ok) {
|
651
|
+
throw new Error("Network response was not ok");
|
652
|
+
}
|
653
|
+
return response.json();
|
654
|
+
}).then((data) => {
|
655
|
+
return data.data.value;
|
656
|
+
}).catch((error) => {
|
657
|
+
console.error("There was a problem with the fetch operation:", error);
|
658
|
+
return fallback;
|
659
|
+
});
|
660
|
+
}
|
661
|
+
try {
|
662
|
+
const existingVals = this.values[contextStr];
|
663
|
+
if (this.conn && typeof existingVals !== "undefined" && typeof existingVals[key] !== "undefined") {
|
664
|
+
return existingVals[key];
|
665
|
+
}
|
666
|
+
try {
|
667
|
+
await this.setContext(context);
|
668
|
+
} catch (error) {
|
669
|
+
console.error(
|
670
|
+
"WebSocket connection failed, falling back to REST:",
|
671
|
+
error
|
672
|
+
);
|
673
|
+
return this.fallbackToRest(key, context, fallback);
|
674
|
+
}
|
675
|
+
const contextVals = this.values[contextStr] ?? {};
|
635
676
|
return typeof contextVals[key] === "undefined" ? fallback : contextVals[key];
|
677
|
+
} catch (error) {
|
678
|
+
console.error("Unexpected error in checkFlag:", error);
|
679
|
+
return fallback;
|
636
680
|
}
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
681
|
+
}
|
682
|
+
/**
|
683
|
+
* Helper method for falling back to REST API when WebSocket connection fails
|
684
|
+
*/
|
685
|
+
async fallbackToRest(key, context, fallback) {
|
686
|
+
try {
|
687
|
+
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
688
|
+
const response = await fetch(requestUrl, {
|
689
|
+
method: "POST",
|
690
|
+
headers: {
|
691
|
+
...this.additionalHeaders ?? {},
|
692
|
+
"Content-Type": "application/json;charset=UTF-8",
|
693
|
+
"X-Schematic-Api-Key": this.apiKey
|
694
|
+
},
|
695
|
+
body: JSON.stringify(context)
|
696
|
+
});
|
647
697
|
if (!response.ok) {
|
648
698
|
throw new Error("Network response was not ok");
|
649
699
|
}
|
650
|
-
|
651
|
-
}).then((data) => {
|
700
|
+
const data = await response.json();
|
652
701
|
return data.data.value;
|
653
|
-
}
|
654
|
-
console.error("
|
702
|
+
} catch (error) {
|
703
|
+
console.error("REST API call failed, using fallback value:", error);
|
655
704
|
return fallback;
|
656
|
-
}
|
705
|
+
}
|
657
706
|
}
|
658
|
-
|
707
|
+
/**
|
708
|
+
* Make an API call to fetch all flag values for a given context.
|
709
|
+
* Recommended for use in REST mode only.
|
710
|
+
*/
|
659
711
|
checkFlags = async (context) => {
|
660
712
|
context = context || this.context;
|
661
713
|
const requestUrl = `${this.apiUrl}/flags/check`;
|
@@ -686,18 +738,30 @@ var Schematic = class {
|
|
686
738
|
return false;
|
687
739
|
});
|
688
740
|
};
|
689
|
-
|
741
|
+
/**
|
742
|
+
* Send an identify event.
|
743
|
+
* This will set the context for subsequent flag evaluation and events, and will also
|
744
|
+
* send an identify event to the Schematic API which will upsert a user and company.
|
745
|
+
*/
|
690
746
|
identify = (body) => {
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
747
|
+
try {
|
748
|
+
this.setContext({
|
749
|
+
company: body.company?.keys,
|
750
|
+
user: body.keys
|
751
|
+
});
|
752
|
+
} catch (error) {
|
753
|
+
console.error("Error setting context:", error);
|
754
|
+
}
|
695
755
|
return this.handleEvent("identify", body);
|
696
756
|
};
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
757
|
+
/**
|
758
|
+
* Set the flag evaluation context.
|
759
|
+
* In WebSocket mode, this will:
|
760
|
+
* 1. Open a websocket connection if not already open
|
761
|
+
* 2. Send the context to the server
|
762
|
+
* 3. Wait for initial flag values to be returned
|
763
|
+
* The promise resolves when initial flag values are received.
|
764
|
+
*/
|
701
765
|
setContext = async (context) => {
|
702
766
|
if (!this.useWebSocket) {
|
703
767
|
this.context = context;
|
@@ -711,10 +775,14 @@ var Schematic = class {
|
|
711
775
|
const socket = await this.conn;
|
712
776
|
await this.wsSendMessage(socket, context);
|
713
777
|
} catch (error) {
|
714
|
-
console.error("
|
778
|
+
console.error("Failed to establish WebSocket connection:", error);
|
779
|
+
throw error;
|
715
780
|
}
|
716
781
|
};
|
717
|
-
|
782
|
+
/**
|
783
|
+
* Send a track event
|
784
|
+
* Track usage for a company and/or user.
|
785
|
+
*/
|
718
786
|
track = (body) => {
|
719
787
|
const { company, user, event, traits } = body;
|
720
788
|
return this.handleEvent("track", {
|
@@ -786,6 +854,9 @@ var Schematic = class {
|
|
786
854
|
/**
|
787
855
|
* Websocket management
|
788
856
|
*/
|
857
|
+
/**
|
858
|
+
* If using websocket mode, close the connection when done.
|
859
|
+
*/
|
789
860
|
cleanup = async () => {
|
790
861
|
if (this.conn) {
|
791
862
|
try {
|
@@ -912,7 +983,7 @@ var notifyListener = (listener, value) => {
|
|
912
983
|
};
|
913
984
|
|
914
985
|
// src/context/schematic.tsx
|
915
|
-
import React, { createContext, useEffect, useMemo } from "react";
|
986
|
+
import React, { createContext, useEffect, useMemo, useRef } from "react";
|
916
987
|
import { jsx } from "react/jsx-runtime";
|
917
988
|
var SchematicContext = createContext(
|
918
989
|
null
|
@@ -923,16 +994,19 @@ var SchematicProvider = ({
|
|
923
994
|
publishableKey,
|
924
995
|
...clientOpts
|
925
996
|
}) => {
|
997
|
+
const initialOptsRef = useRef({
|
998
|
+
publishableKey,
|
999
|
+
useWebSocket: clientOpts.useWebSocket ?? true,
|
1000
|
+
...clientOpts
|
1001
|
+
});
|
926
1002
|
const client = useMemo(() => {
|
927
|
-
const { useWebSocket = true } = clientOpts;
|
928
1003
|
if (providedClient) {
|
929
1004
|
return providedClient;
|
930
1005
|
}
|
931
|
-
return new Schematic(publishableKey, {
|
932
|
-
|
933
|
-
...clientOpts
|
1006
|
+
return new Schematic(initialOptsRef.current.publishableKey, {
|
1007
|
+
...initialOptsRef.current
|
934
1008
|
});
|
935
|
-
}, [providedClient
|
1009
|
+
}, [providedClient]);
|
936
1010
|
useEffect(() => {
|
937
1011
|
return () => {
|
938
1012
|
if (!providedClient) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@schematichq/schematic-react",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.3",
|
4
4
|
"main": "dist/schematic-react.cjs.js",
|
5
5
|
"module": "dist/schematic-react.esm.js",
|
6
6
|
"types": "dist/schematic-react.d.ts",
|
@@ -40,7 +40,7 @@
|
|
40
40
|
"esbuild-jest": "^0.5.0",
|
41
41
|
"eslint": "^8.57.1",
|
42
42
|
"eslint-plugin-import": "^2.30.0",
|
43
|
-
"eslint-plugin-react-hooks": "^
|
43
|
+
"eslint-plugin-react-hooks": "^5.0.0",
|
44
44
|
"jest": "^29.7.0",
|
45
45
|
"jest-environment-jsdom": "^29.7.0",
|
46
46
|
"jest-esbuild": "^0.3.0",
|