@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 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",