@schematichq/schematic-react 1.0.0-rc.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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",
|