@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 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 i = 0; i < view.length; i++) {
234
- chars[i] = String.fromCharCode(view[i]);
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
- const rnds = options.random || (options.rng || rng)();
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 (let i = 0; i < 16; ++i) {
602
- buf[offset + i] = rnds[i];
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
- "X-Schematic-Api-Key": this.apiKey,
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((listener) => listener());
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 i = 0; i < view.length; i++) {
192
- chars[i] = String.fromCharCode(view[i]);
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
- const rnds = options.random || (options.rng || rng)();
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 (let i = 0; i < 16; ++i) {
560
- buf[offset + i] = rnds[i];
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
- "X-Schematic-Api-Key": this.apiKey,
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((listener) => listener());
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.0-rc.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 openapi && yarn format && yarn lint && yarn clean && yarn build:cjs && yarn build:esm && yarn build:types",
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.1.14"
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",