@schematichq/schematic-react 1.0.0-rc.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +86 -0
- package/dist/schematic-react.cjs.js +36 -20
- package/dist/schematic-react.esm.js +36 -20
- package/package.json +3 -5
package/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# schematic-react
|
2
|
+
|
3
|
+
`schematic-react` is a client-side React library for [Schematic](https://schematichq.com) which provides hooks to track events, check flags, and more. `schematic-react` provides the same capabilities as [schematic-js](https://github.com/schematichq/schematic-js/tree/main/js), for React apps.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
```bash
|
8
|
+
npm install @schematichq/schematic-react
|
9
|
+
# or
|
10
|
+
yarn add @schematichq/schematic-react
|
11
|
+
# or
|
12
|
+
pnpm add @schematichq/schematic-react
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
You can use the `SchematicProvider` to wrap your application and provide the Schematic instance to all components:
|
18
|
+
|
19
|
+
```tsx
|
20
|
+
import { SchematicProvider } from "@schematichq/schematic-react";
|
21
|
+
|
22
|
+
ReactDOM.render(
|
23
|
+
<SchematicProvider publishableKey="your-publishable-key">
|
24
|
+
<App />
|
25
|
+
</SchematicProvider>,
|
26
|
+
document.getElementById("root"),
|
27
|
+
);
|
28
|
+
```
|
29
|
+
|
30
|
+
To set the user context for events and flag checks, you can use the `identify` function provided by the `useSchematicEvents` hook:
|
31
|
+
|
32
|
+
```tsx
|
33
|
+
import { useSchematicEvents } from "@schematichq/schematic-react";
|
34
|
+
|
35
|
+
const MyComponent = () => {
|
36
|
+
const { identify } = useSchematicEvents();
|
37
|
+
|
38
|
+
useEffect(() => {
|
39
|
+
identify({
|
40
|
+
keys: { id: "my-user-id" },
|
41
|
+
company: {
|
42
|
+
keys: { id: "my-company-id" },
|
43
|
+
traits: { location: "Atlanta, GA" },
|
44
|
+
},
|
45
|
+
});
|
46
|
+
}, []);
|
47
|
+
|
48
|
+
return <div>My Component</div>;
|
49
|
+
};
|
50
|
+
```
|
51
|
+
|
52
|
+
Once you've set the context with `identify`, you can track events:
|
53
|
+
|
54
|
+
```tsx
|
55
|
+
import { useSchematicEvents } from "@schematichq/schematic-react";
|
56
|
+
|
57
|
+
const MyComponent = () => {
|
58
|
+
const { track } = useSchematicEvents();
|
59
|
+
|
60
|
+
useEffect(() => {
|
61
|
+
track({ event: "query" });
|
62
|
+
}, []);
|
63
|
+
|
64
|
+
return <div>My Component</div>;
|
65
|
+
};
|
66
|
+
```
|
67
|
+
|
68
|
+
To check a flag, you can use the `useSchematicFlags` hook:
|
69
|
+
|
70
|
+
```tsx
|
71
|
+
import { useSchematicFlag } from "@schematichq/schematic-react";
|
72
|
+
|
73
|
+
const MyComponent = () => {
|
74
|
+
const isFeatureEnabled = useSchematicFlag("my-flag-key");
|
75
|
+
|
76
|
+
return isFeatureEnabled ? <Feature /> : <Fallback />;
|
77
|
+
};
|
78
|
+
```
|
79
|
+
|
80
|
+
## License
|
81
|
+
|
82
|
+
MIT
|
83
|
+
|
84
|
+
## Support
|
85
|
+
|
86
|
+
Need help? Please open a GitHub issue or reach out to [support@schematichq.com](mailto:support@schematichq.com) and we'll be happy to assist.
|
@@ -230,8 +230,8 @@ var require_browser_polyfill = __commonJS({
|
|
230
230
|
function readArrayBufferAsText(buf) {
|
231
231
|
var view = new Uint8Array(buf);
|
232
232
|
var chars = new Array(view.length);
|
233
|
-
for (var
|
234
|
-
chars[
|
233
|
+
for (var i2 = 0; i2 < view.length; i2++) {
|
234
|
+
chars[i2] = String.fromCharCode(view[i2]);
|
235
235
|
}
|
236
236
|
return chars.join("");
|
237
237
|
}
|
@@ -566,6 +566,14 @@ var require_browser_polyfill = __commonJS({
|
|
566
566
|
})(typeof self !== "undefined" ? self : exports);
|
567
567
|
}
|
568
568
|
});
|
569
|
+
var byteToHex = [];
|
570
|
+
for (i = 0; i < 256; ++i) {
|
571
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
572
|
+
}
|
573
|
+
var i;
|
574
|
+
function unsafeStringify(arr, offset = 0) {
|
575
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
576
|
+
}
|
569
577
|
var getRandomValues;
|
570
578
|
var rnds8 = new Uint8Array(16);
|
571
579
|
function rng() {
|
@@ -577,13 +585,6 @@ function rng() {
|
|
577
585
|
}
|
578
586
|
return getRandomValues(rnds8);
|
579
587
|
}
|
580
|
-
var byteToHex = [];
|
581
|
-
for (let i = 0; i < 256; ++i) {
|
582
|
-
byteToHex.push((i + 256).toString(16).slice(1));
|
583
|
-
}
|
584
|
-
function unsafeStringify(arr, offset = 0) {
|
585
|
-
return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
|
586
|
-
}
|
587
588
|
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
588
589
|
var native_default = {
|
589
590
|
randomUUID
|
@@ -593,13 +594,13 @@ function v4(options, buf, offset) {
|
|
593
594
|
return native_default.randomUUID();
|
594
595
|
}
|
595
596
|
options = options || {};
|
596
|
-
|
597
|
+
var rnds = options.random || (options.rng || rng)();
|
597
598
|
rnds[6] = rnds[6] & 15 | 64;
|
598
599
|
rnds[8] = rnds[8] & 63 | 128;
|
599
600
|
if (buf) {
|
600
601
|
offset = offset || 0;
|
601
|
-
for (
|
602
|
-
buf[offset +
|
602
|
+
for (var i2 = 0; i2 < 16; ++i2) {
|
603
|
+
buf[offset + i2] = rnds[i2];
|
603
604
|
}
|
604
605
|
return buf;
|
605
606
|
}
|
@@ -623,6 +624,7 @@ function contextString(context) {
|
|
623
624
|
}
|
624
625
|
var anonymousIdKey = "schematicId";
|
625
626
|
var Schematic = class {
|
627
|
+
additionalHeaders = {};
|
626
628
|
apiKey;
|
627
629
|
apiUrl = "https://api.schematichq.com";
|
628
630
|
conn = null;
|
@@ -642,6 +644,9 @@ var Schematic = class {
|
|
642
644
|
this.eventQueue = [];
|
643
645
|
this.useWebSocket = options?.useWebSocket ?? false;
|
644
646
|
this.flagListener = options?.flagListener;
|
647
|
+
if (options?.additionalHeaders) {
|
648
|
+
this.additionalHeaders = options.additionalHeaders;
|
649
|
+
}
|
645
650
|
if (options?.storage) {
|
646
651
|
this.storage = options.storage;
|
647
652
|
} else if (typeof localStorage !== "undefined") {
|
@@ -675,8 +680,9 @@ var Schematic = class {
|
|
675
680
|
return fetch(requestUrl, {
|
676
681
|
method: "POST",
|
677
682
|
headers: {
|
678
|
-
|
679
|
-
"Content-Type": "application/json;charset=UTF-8"
|
683
|
+
...this.additionalHeaders ?? {},
|
684
|
+
"Content-Type": "application/json;charset=UTF-8",
|
685
|
+
"X-Schematic-Api-Key": this.apiKey
|
680
686
|
},
|
681
687
|
body: JSON.stringify(context)
|
682
688
|
}).then((response) => {
|
@@ -699,6 +705,7 @@ var Schematic = class {
|
|
699
705
|
return fetch(requestUrl, {
|
700
706
|
method: "POST",
|
701
707
|
headers: {
|
708
|
+
...this.additionalHeaders ?? {},
|
702
709
|
"Content-Type": "application/json;charset=UTF-8",
|
703
710
|
"X-Schematic-Api-Key": this.apiKey
|
704
711
|
},
|
@@ -804,6 +811,7 @@ var Schematic = class {
|
|
804
811
|
await fetch(captureUrl, {
|
805
812
|
method: "POST",
|
806
813
|
headers: {
|
814
|
+
...this.additionalHeaders ?? {},
|
807
815
|
"Content-Type": "application/json;charset=UTF-8"
|
808
816
|
},
|
809
817
|
body: payload
|
@@ -853,8 +861,7 @@ var Schematic = class {
|
|
853
861
|
wsSendMessage = (socket, context) => {
|
854
862
|
return new Promise((resolve, reject) => {
|
855
863
|
if (contextString(context) == contextString(this.context)) {
|
856
|
-
resolve();
|
857
|
-
return;
|
864
|
+
return resolve(this.setIsPending(false));
|
858
865
|
}
|
859
866
|
this.context = context;
|
860
867
|
const sendMessage = () => {
|
@@ -867,7 +874,7 @@ var Schematic = class {
|
|
867
874
|
(message.flags ?? []).forEach(
|
868
875
|
(flag) => {
|
869
876
|
this.values[contextString(context)][flag.flag] = flag.value;
|
870
|
-
this.notifyFlagValueListeners(flag.flag);
|
877
|
+
this.notifyFlagValueListeners(flag.flag, flag.value);
|
871
878
|
}
|
872
879
|
);
|
873
880
|
if (this.flagListener) {
|
@@ -911,7 +918,9 @@ var Schematic = class {
|
|
911
918
|
};
|
912
919
|
setIsPending = (isPending) => {
|
913
920
|
this.isPending = isPending;
|
914
|
-
this.isPendingListeners.forEach(
|
921
|
+
this.isPendingListeners.forEach(
|
922
|
+
(listener) => notifyListener(listener, isPending)
|
923
|
+
);
|
915
924
|
};
|
916
925
|
// flagValues state
|
917
926
|
getFlagValue = (flagKey) => {
|
@@ -931,11 +940,18 @@ var Schematic = class {
|
|
931
940
|
this.flagValueListeners[flagKey].delete(listener);
|
932
941
|
};
|
933
942
|
};
|
934
|
-
notifyFlagValueListeners = (flagKey) => {
|
943
|
+
notifyFlagValueListeners = (flagKey, value) => {
|
935
944
|
const listeners = this.flagValueListeners?.[flagKey] ?? [];
|
936
|
-
listeners.forEach((listener) => listener
|
945
|
+
listeners.forEach((listener) => notifyListener(listener, value));
|
937
946
|
};
|
938
947
|
};
|
948
|
+
var notifyListener = (listener, value) => {
|
949
|
+
if (listener.length > 0) {
|
950
|
+
listener(value);
|
951
|
+
} else {
|
952
|
+
listener();
|
953
|
+
}
|
954
|
+
};
|
939
955
|
|
940
956
|
// src/context/schematic.tsx
|
941
957
|
var import_react = __toESM(require("react"));
|
@@ -188,8 +188,8 @@ var require_browser_polyfill = __commonJS({
|
|
188
188
|
function readArrayBufferAsText(buf) {
|
189
189
|
var view = new Uint8Array(buf);
|
190
190
|
var chars = new Array(view.length);
|
191
|
-
for (var
|
192
|
-
chars[
|
191
|
+
for (var i2 = 0; i2 < view.length; i2++) {
|
192
|
+
chars[i2] = String.fromCharCode(view[i2]);
|
193
193
|
}
|
194
194
|
return chars.join("");
|
195
195
|
}
|
@@ -524,6 +524,14 @@ var require_browser_polyfill = __commonJS({
|
|
524
524
|
})(typeof self !== "undefined" ? self : exports);
|
525
525
|
}
|
526
526
|
});
|
527
|
+
var byteToHex = [];
|
528
|
+
for (i = 0; i < 256; ++i) {
|
529
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
530
|
+
}
|
531
|
+
var i;
|
532
|
+
function unsafeStringify(arr, offset = 0) {
|
533
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
534
|
+
}
|
527
535
|
var getRandomValues;
|
528
536
|
var rnds8 = new Uint8Array(16);
|
529
537
|
function rng() {
|
@@ -535,13 +543,6 @@ function rng() {
|
|
535
543
|
}
|
536
544
|
return getRandomValues(rnds8);
|
537
545
|
}
|
538
|
-
var byteToHex = [];
|
539
|
-
for (let i = 0; i < 256; ++i) {
|
540
|
-
byteToHex.push((i + 256).toString(16).slice(1));
|
541
|
-
}
|
542
|
-
function unsafeStringify(arr, offset = 0) {
|
543
|
-
return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
|
544
|
-
}
|
545
546
|
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
546
547
|
var native_default = {
|
547
548
|
randomUUID
|
@@ -551,13 +552,13 @@ function v4(options, buf, offset) {
|
|
551
552
|
return native_default.randomUUID();
|
552
553
|
}
|
553
554
|
options = options || {};
|
554
|
-
|
555
|
+
var rnds = options.random || (options.rng || rng)();
|
555
556
|
rnds[6] = rnds[6] & 15 | 64;
|
556
557
|
rnds[8] = rnds[8] & 63 | 128;
|
557
558
|
if (buf) {
|
558
559
|
offset = offset || 0;
|
559
|
-
for (
|
560
|
-
buf[offset +
|
560
|
+
for (var i2 = 0; i2 < 16; ++i2) {
|
561
|
+
buf[offset + i2] = rnds[i2];
|
561
562
|
}
|
562
563
|
return buf;
|
563
564
|
}
|
@@ -581,6 +582,7 @@ function contextString(context) {
|
|
581
582
|
}
|
582
583
|
var anonymousIdKey = "schematicId";
|
583
584
|
var Schematic = class {
|
585
|
+
additionalHeaders = {};
|
584
586
|
apiKey;
|
585
587
|
apiUrl = "https://api.schematichq.com";
|
586
588
|
conn = null;
|
@@ -600,6 +602,9 @@ var Schematic = class {
|
|
600
602
|
this.eventQueue = [];
|
601
603
|
this.useWebSocket = options?.useWebSocket ?? false;
|
602
604
|
this.flagListener = options?.flagListener;
|
605
|
+
if (options?.additionalHeaders) {
|
606
|
+
this.additionalHeaders = options.additionalHeaders;
|
607
|
+
}
|
603
608
|
if (options?.storage) {
|
604
609
|
this.storage = options.storage;
|
605
610
|
} else if (typeof localStorage !== "undefined") {
|
@@ -633,8 +638,9 @@ var Schematic = class {
|
|
633
638
|
return fetch(requestUrl, {
|
634
639
|
method: "POST",
|
635
640
|
headers: {
|
636
|
-
|
637
|
-
"Content-Type": "application/json;charset=UTF-8"
|
641
|
+
...this.additionalHeaders ?? {},
|
642
|
+
"Content-Type": "application/json;charset=UTF-8",
|
643
|
+
"X-Schematic-Api-Key": this.apiKey
|
638
644
|
},
|
639
645
|
body: JSON.stringify(context)
|
640
646
|
}).then((response) => {
|
@@ -657,6 +663,7 @@ var Schematic = class {
|
|
657
663
|
return fetch(requestUrl, {
|
658
664
|
method: "POST",
|
659
665
|
headers: {
|
666
|
+
...this.additionalHeaders ?? {},
|
660
667
|
"Content-Type": "application/json;charset=UTF-8",
|
661
668
|
"X-Schematic-Api-Key": this.apiKey
|
662
669
|
},
|
@@ -762,6 +769,7 @@ var Schematic = class {
|
|
762
769
|
await fetch(captureUrl, {
|
763
770
|
method: "POST",
|
764
771
|
headers: {
|
772
|
+
...this.additionalHeaders ?? {},
|
765
773
|
"Content-Type": "application/json;charset=UTF-8"
|
766
774
|
},
|
767
775
|
body: payload
|
@@ -811,8 +819,7 @@ var Schematic = class {
|
|
811
819
|
wsSendMessage = (socket, context) => {
|
812
820
|
return new Promise((resolve, reject) => {
|
813
821
|
if (contextString(context) == contextString(this.context)) {
|
814
|
-
resolve();
|
815
|
-
return;
|
822
|
+
return resolve(this.setIsPending(false));
|
816
823
|
}
|
817
824
|
this.context = context;
|
818
825
|
const sendMessage = () => {
|
@@ -825,7 +832,7 @@ var Schematic = class {
|
|
825
832
|
(message.flags ?? []).forEach(
|
826
833
|
(flag) => {
|
827
834
|
this.values[contextString(context)][flag.flag] = flag.value;
|
828
|
-
this.notifyFlagValueListeners(flag.flag);
|
835
|
+
this.notifyFlagValueListeners(flag.flag, flag.value);
|
829
836
|
}
|
830
837
|
);
|
831
838
|
if (this.flagListener) {
|
@@ -869,7 +876,9 @@ var Schematic = class {
|
|
869
876
|
};
|
870
877
|
setIsPending = (isPending) => {
|
871
878
|
this.isPending = isPending;
|
872
|
-
this.isPendingListeners.forEach(
|
879
|
+
this.isPendingListeners.forEach(
|
880
|
+
(listener) => notifyListener(listener, isPending)
|
881
|
+
);
|
873
882
|
};
|
874
883
|
// flagValues state
|
875
884
|
getFlagValue = (flagKey) => {
|
@@ -889,11 +898,18 @@ var Schematic = class {
|
|
889
898
|
this.flagValueListeners[flagKey].delete(listener);
|
890
899
|
};
|
891
900
|
};
|
892
|
-
notifyFlagValueListeners = (flagKey) => {
|
901
|
+
notifyFlagValueListeners = (flagKey, value) => {
|
893
902
|
const listeners = this.flagValueListeners?.[flagKey] ?? [];
|
894
|
-
listeners.forEach((listener) => listener
|
903
|
+
listeners.forEach((listener) => notifyListener(listener, value));
|
895
904
|
};
|
896
905
|
};
|
906
|
+
var notifyListener = (listener, value) => {
|
907
|
+
if (listener.length > 0) {
|
908
|
+
listener(value);
|
909
|
+
} else {
|
910
|
+
listener();
|
911
|
+
}
|
912
|
+
};
|
897
913
|
|
898
914
|
// src/context/schematic.tsx
|
899
915
|
import React, { createContext, useEffect, useMemo } from "react";
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@schematichq/schematic-react",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.2",
|
4
4
|
"main": "dist/schematic-react.cjs.js",
|
5
5
|
"module": "dist/schematic-react.esm.js",
|
6
6
|
"types": "dist/schematic-react.d.ts",
|
@@ -17,23 +17,21 @@
|
|
17
17
|
},
|
18
18
|
"scripts": {
|
19
19
|
"dev": "yarn tsc --watch",
|
20
|
-
"build": "yarn tsc && yarn
|
20
|
+
"build": "yarn tsc && yarn format && yarn lint && yarn clean && yarn build:cjs && yarn build:esm && yarn build:types",
|
21
21
|
"build:cjs": "npx esbuild src/index.ts --bundle --external:react --format=cjs --outfile=dist/schematic-react.cjs.js",
|
22
22
|
"build:esm": "npx esbuild src/index.ts --bundle --external:react --format=esm --outfile=dist/schematic-react.esm.js",
|
23
23
|
"build:types": "npx tsc && npx api-extractor run",
|
24
24
|
"clean": "rm -rf dist",
|
25
25
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
26
26
|
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --fix",
|
27
|
-
"openapi": "rm -rf src/api/ && npx openapi-generator-cli generate -c openapi-config.yaml && prettier --write \"src/api/**/*.{ts,tsx}\"",
|
28
27
|
"test": "jest --config jest.config.js",
|
29
28
|
"tsc": "npx tsc"
|
30
29
|
},
|
31
30
|
"dependencies": {
|
32
|
-
"@schematichq/schematic-js": "^0.
|
31
|
+
"@schematichq/schematic-js": "^1.0.2"
|
33
32
|
},
|
34
33
|
"devDependencies": {
|
35
34
|
"@microsoft/api-extractor": "^7.47.9",
|
36
|
-
"@openapitools/openapi-generator-cli": "^2.13.9",
|
37
35
|
"@types/jest": "^29.5.13",
|
38
36
|
"@types/react": "^18.3.9",
|
39
37
|
"@typescript-eslint/eslint-plugin": "^8.7.0",
|