@schematichq/schematic-react 1.2.17 → 1.3.0

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.
@@ -39,7 +39,8 @@ __export(index_exports, {
39
39
  useSchematicEntitlement: () => useSchematicEntitlement,
40
40
  useSchematicEvents: () => useSchematicEvents,
41
41
  useSchematicFlag: () => useSchematicFlag,
42
- useSchematicIsPending: () => useSchematicIsPending
42
+ useSchematicIsPending: () => useSchematicIsPending,
43
+ useSchematicPlan: () => useSchematicPlan
43
44
  });
44
45
  module.exports = __toCommonJS(index_exports);
45
46
 
@@ -651,6 +652,36 @@ function v4(options, buf, offset) {
651
652
  }
652
653
  var v4_default = v4;
653
654
  var import_polyfill = __toESM2(require_browser_polyfill());
655
+ function EntitlementValueTypeFromJSON(json) {
656
+ return EntitlementValueTypeFromJSONTyped(json, false);
657
+ }
658
+ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
659
+ return json;
660
+ }
661
+ function FeatureEntitlementFromJSON(json) {
662
+ return FeatureEntitlementFromJSONTyped(json, false);
663
+ }
664
+ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
665
+ if (json == null) {
666
+ return json;
667
+ }
668
+ return {
669
+ allocation: json["allocation"] == null ? void 0 : json["allocation"],
670
+ creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
671
+ creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
672
+ creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
673
+ creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
674
+ eventName: json["event_name"] == null ? void 0 : json["event_name"],
675
+ featureId: json["feature_id"],
676
+ featureKey: json["feature_key"],
677
+ metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
678
+ metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
679
+ monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
680
+ softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
681
+ usage: json["usage"] == null ? void 0 : json["usage"],
682
+ valueType: EntitlementValueTypeFromJSON(json["value_type"])
683
+ };
684
+ }
654
685
  function CheckFlagResponseDataFromJSON(json) {
655
686
  return CheckFlagResponseDataFromJSONTyped(json, false);
656
687
  }
@@ -660,6 +691,7 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
660
691
  }
661
692
  return {
662
693
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
694
+ entitlement: json["entitlement"] == null ? void 0 : FeatureEntitlementFromJSON(json["entitlement"]),
663
695
  error: json["error"] == null ? void 0 : json["error"],
664
696
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
665
697
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
@@ -675,26 +707,6 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
675
707
  value: json["value"]
676
708
  };
677
709
  }
678
- function EventBodyFlagCheckToJSON(json) {
679
- return EventBodyFlagCheckToJSONTyped(json, false);
680
- }
681
- function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
682
- if (value == null) {
683
- return value;
684
- }
685
- return {
686
- company_id: value["companyId"],
687
- error: value["error"],
688
- flag_id: value["flagId"],
689
- flag_key: value["flagKey"],
690
- reason: value["reason"],
691
- req_company: value["reqCompany"],
692
- req_user: value["reqUser"],
693
- rule_id: value["ruleId"],
694
- user_id: value["userId"],
695
- value: value["value"]
696
- };
697
- }
698
710
  function CheckFlagResponseFromJSON(json) {
699
711
  return CheckFlagResponseFromJSONTyped(json, false);
700
712
  }
@@ -707,6 +719,19 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
707
719
  params: json["params"]
708
720
  };
709
721
  }
722
+ function DatastreamCompanyPlanFromJSON(json) {
723
+ return DatastreamCompanyPlanFromJSONTyped(json, false);
724
+ }
725
+ function DatastreamCompanyPlanFromJSONTyped(json, ignoreDiscriminator) {
726
+ if (json == null) {
727
+ return json;
728
+ }
729
+ return {
730
+ id: json["id"],
731
+ name: json["name"],
732
+ trialEndDate: json["trial_end_date"] == null ? void 0 : new Date(json["trial_end_date"])
733
+ };
734
+ }
710
735
  function CheckFlagsResponseDataFromJSON(json) {
711
736
  return CheckFlagsResponseDataFromJSONTyped(json, false);
712
737
  }
@@ -715,7 +740,8 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
715
740
  return json;
716
741
  }
717
742
  return {
718
- flags: json["flags"].map(CheckFlagResponseDataFromJSON)
743
+ flags: json["flags"].map(CheckFlagResponseDataFromJSON),
744
+ plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
719
745
  };
720
746
  }
721
747
  function CheckFlagsResponseFromJSON(json) {
@@ -730,6 +756,26 @@ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
730
756
  params: json["params"]
731
757
  };
732
758
  }
759
+ function EventBodyFlagCheckToJSON(json) {
760
+ return EventBodyFlagCheckToJSONTyped(json, false);
761
+ }
762
+ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
763
+ if (value == null) {
764
+ return value;
765
+ }
766
+ return {
767
+ company_id: value["companyId"],
768
+ error: value["error"],
769
+ flag_id: value["flagId"],
770
+ flag_key: value["flagKey"],
771
+ reason: value["reason"],
772
+ req_company: value["reqCompany"],
773
+ req_user: value["reqUser"],
774
+ rule_id: value["ruleId"],
775
+ user_id: value["userId"],
776
+ value: value["value"]
777
+ };
778
+ }
733
779
  var RuleType = /* @__PURE__ */ ((RuleType2) => {
734
780
  RuleType2["GLOBAL_OVERRIDE"] = "global_override";
735
781
  RuleType2["COMPANY_OVERRIDE"] = "company_override";
@@ -785,6 +831,14 @@ var CheckFlagReturnFromJSON = (json) => {
785
831
  value
786
832
  };
787
833
  };
834
+ var CheckPlanReturnFromJSON = (json) => {
835
+ const { id, name, trialEndDate } = DatastreamCompanyPlanFromJSON(json);
836
+ return {
837
+ id,
838
+ name,
839
+ trialEndDate: trialEndDate == null ? void 0 : trialEndDate
840
+ };
841
+ };
788
842
  function contextString(context) {
789
843
  const sortedContext = Object.keys(context).reduce((acc, key) => {
790
844
  const sortedKeys = Object.keys(
@@ -799,7 +853,7 @@ function contextString(context) {
799
853
  }, {});
800
854
  return JSON.stringify(sortedContext);
801
855
  }
802
- var version = "1.2.17";
856
+ var version = "1.3.0";
803
857
  var anonymousIdKey = "schematicId";
804
858
  var Schematic = class {
805
859
  additionalHeaders = {};
@@ -816,10 +870,12 @@ var Schematic = class {
816
870
  flagValueListeners = {};
817
871
  isPending = true;
818
872
  isPendingListeners = /* @__PURE__ */ new Set();
873
+ planListeners = /* @__PURE__ */ new Set();
819
874
  storage;
820
875
  useWebSocket = false;
821
876
  checks = {};
822
877
  featureUsageEventMap = {};
878
+ planChecks = {};
823
879
  webSocketUrl = "wss://api.schematichq.com";
824
880
  webSocketConnectionTimeout = 1e4;
825
881
  webSocketReconnect = true;
@@ -845,6 +901,7 @@ var Schematic = class {
845
901
  retryTimer = null;
846
902
  flagValueDefaults = {};
847
903
  flagCheckDefaults = {};
904
+ fallbackCheckCache = {};
848
905
  constructor(apiKey, options) {
849
906
  this.apiKey = apiKey;
850
907
  this.eventQueue = [];
@@ -1104,6 +1161,13 @@ var Schematic = class {
1104
1161
  );
1105
1162
  if (typeof flagCheck !== "undefined") {
1106
1163
  this.submitFlagCheckEvent(key, flagCheck, context);
1164
+ } else {
1165
+ const fallbackResult = this.resolveFallbackCheckFlagReturn(
1166
+ key,
1167
+ fallback,
1168
+ "No flag values available"
1169
+ );
1170
+ this.submitFlagCheckEvent(key, fallbackResult, context);
1107
1171
  }
1108
1172
  return result;
1109
1173
  } catch (error) {
@@ -1144,28 +1208,32 @@ var Schematic = class {
1144
1208
  this.checks[contextStr] = {};
1145
1209
  }
1146
1210
  this.checks[contextStr][flagCheck.flag] = flagCheck;
1147
- this.debug(`WebSocket flag update:`, {
1148
- flag: flagCheck.flag,
1149
- value: flagCheck.value,
1150
- flagCheck
1151
- });
1152
1211
  if (typeof flagCheck.featureUsageEvent === "string") {
1153
1212
  this.updateFeatureUsageEventMap(flagCheck);
1154
1213
  }
1155
1214
  if ((this.flagCheckListeners[flag.flag]?.size ?? 0) > 0 || (this.flagValueListeners[flag.flag]?.size ?? 0) > 0) {
1156
1215
  this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
1157
1216
  }
1158
- this.debug(`About to notify listeners for flag ${flag.flag}`, {
1159
- flag: flag.flag,
1160
- value: flagCheck.value
1161
- });
1217
+ this.debug(
1218
+ `WebSocket flag update received. Notifying listeners for ${flag.flag}`,
1219
+ {
1220
+ flag: flag.flag,
1221
+ value: flagCheck.value,
1222
+ flagCheck
1223
+ }
1224
+ );
1162
1225
  this.notifyFlagCheckListeners(flag.flag, flagCheck);
1163
1226
  this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1164
- this.debug(`Finished notifying listeners for flag ${flag.flag}`, {
1165
- flag: flag.flag,
1166
- value: flagCheck.value
1167
- });
1168
1227
  });
1228
+ if (message.plan !== void 0 && message.plan !== null) {
1229
+ const plan = CheckPlanReturnFromJSON(message.plan);
1230
+ const contextStr = contextString(context);
1231
+ this.planChecks[contextStr] = plan;
1232
+ this.debug(`WebSocket plan update received. Notifying listeners`, {
1233
+ plan
1234
+ });
1235
+ this.notifyPlanListeners(plan);
1236
+ }
1169
1237
  this.flushContextDependentEventQueue();
1170
1238
  this.setIsPending(false);
1171
1239
  };
@@ -1269,6 +1337,9 @@ var Schematic = class {
1269
1337
  this.setIsPending(false);
1270
1338
  return Promise.resolve();
1271
1339
  }
1340
+ if (contextString(context) === contextString(this.context) && this.conn !== null && !this.isPending) {
1341
+ return;
1342
+ }
1272
1343
  try {
1273
1344
  this.setIsPending(true);
1274
1345
  if (!this.conn) {
@@ -1308,7 +1379,10 @@ var Schematic = class {
1308
1379
  await this.wsSendMessage(socket, context);
1309
1380
  } catch (error) {
1310
1381
  console.warn("Failed to establish WebSocket connection:", error);
1311
- throw error;
1382
+ this.context = context;
1383
+ this.flushContextDependentEventQueue();
1384
+ this.setIsPending(false);
1385
+ this.attemptReconnect();
1312
1386
  }
1313
1387
  };
1314
1388
  /**
@@ -2049,11 +2123,17 @@ var Schematic = class {
2049
2123
  };
2050
2124
  };
2051
2125
  setIsPending = (isPending) => {
2126
+ if (this.isPending === isPending) return;
2052
2127
  this.isPending = isPending;
2053
2128
  this.isPendingListeners.forEach(
2054
2129
  (listener) => notifyPendingListener(listener, isPending)
2055
2130
  );
2056
2131
  };
2132
+ getPlan = () => {
2133
+ const contextStr = contextString(this.context);
2134
+ const plan = this.planChecks[contextStr];
2135
+ return plan;
2136
+ };
2057
2137
  // flag checks state
2058
2138
  getFlagCheck = (flagKey) => {
2059
2139
  const contextStr = contextString(this.context);
@@ -2063,11 +2143,14 @@ var Schematic = class {
2063
2143
  return check;
2064
2144
  }
2065
2145
  if (flagKey in this.flagCheckDefaults || flagKey in this.flagValueDefaults) {
2066
- return this.resolveFallbackCheckFlagReturn(
2067
- flagKey,
2068
- void 0,
2069
- "Default value used"
2070
- );
2146
+ if (!(flagKey in this.fallbackCheckCache)) {
2147
+ this.fallbackCheckCache[flagKey] = this.resolveFallbackCheckFlagReturn(
2148
+ flagKey,
2149
+ void 0,
2150
+ "Default value used"
2151
+ );
2152
+ }
2153
+ return this.fallbackCheckCache[flagKey];
2071
2154
  }
2072
2155
  return void 0;
2073
2156
  };
@@ -2104,6 +2187,12 @@ var Schematic = class {
2104
2187
  this.flagCheckListeners[flagKey].delete(listener);
2105
2188
  };
2106
2189
  };
2190
+ addPlanListener = (listener) => {
2191
+ this.planListeners.add(listener);
2192
+ return () => {
2193
+ this.planListeners.delete(listener);
2194
+ };
2195
+ };
2107
2196
  notifyFlagCheckListeners = (flagKey, check) => {
2108
2197
  const listeners = this.flagCheckListeners?.[flagKey] ?? [];
2109
2198
  if (listeners.size > 0) {
@@ -2152,6 +2241,21 @@ var Schematic = class {
2152
2241
  });
2153
2242
  });
2154
2243
  };
2244
+ notifyPlanListeners = (value) => {
2245
+ const listeners = this.planListeners ?? [];
2246
+ if (listeners.size > 0) {
2247
+ this.debug(`Notifying ${listeners.size} plan listeners`, { value });
2248
+ }
2249
+ listeners.forEach((listener, index) => {
2250
+ this.debug(`Calling listener ${index} for plan`, {
2251
+ value
2252
+ });
2253
+ notifyPlanListener(listener, value);
2254
+ this.debug(`Listener ${index} for plan completed`, {
2255
+ value
2256
+ });
2257
+ });
2258
+ };
2155
2259
  };
2156
2260
  var notifyPendingListener = (listener, value) => {
2157
2261
  if (listener.length > 0) {
@@ -2174,12 +2278,19 @@ var notifyFlagValueListener = (listener, value) => {
2174
2278
  listener();
2175
2279
  }
2176
2280
  };
2281
+ var notifyPlanListener = (listener, value) => {
2282
+ if (listener.length > 0) {
2283
+ listener(value);
2284
+ } else {
2285
+ listener();
2286
+ }
2287
+ };
2177
2288
 
2178
2289
  // src/context/schematic.tsx
2179
2290
  var import_react = __toESM(require("react"));
2180
2291
 
2181
2292
  // src/version.ts
2182
- var version2 = "1.2.17";
2293
+ var version2 = "1.3.0";
2183
2294
 
2184
2295
  // src/context/schematic.tsx
2185
2296
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -2300,6 +2411,23 @@ var useSchematicEntitlement = (key, opts) => {
2300
2411
  }, [client, key, fallbackCheck]);
2301
2412
  return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackCheck);
2302
2413
  };
2414
+ var useSchematicPlan = (opts) => {
2415
+ const client = useSchematicClient(opts);
2416
+ const fallback = opts?.fallback;
2417
+ const fallbackPlan = (0, import_react2.useMemo)(
2418
+ () => fallback,
2419
+ [fallback?.id, fallback?.name, fallback?.trialEndDate?.getTime()]
2420
+ );
2421
+ const subscribe = (0, import_react2.useCallback)(
2422
+ (callback) => client.addPlanListener(callback),
2423
+ [client]
2424
+ );
2425
+ const getSnapshot = (0, import_react2.useCallback)(() => {
2426
+ const plan = client.getPlan();
2427
+ return plan ?? fallbackPlan;
2428
+ }, [client, fallbackPlan]);
2429
+ return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackPlan);
2430
+ };
2303
2431
  var useSchematicIsPending = (opts) => {
2304
2432
  const client = useSchematicClient(opts);
2305
2433
  const subscribe = (0, import_react2.useCallback)(
@@ -1,4 +1,5 @@
1
1
  import { CheckFlagReturn } from '@schematichq/schematic-js';
2
+ import { CheckPlanReturn } from '@schematichq/schematic-js';
2
3
  import { Event as Event_2 } from '@schematichq/schematic-js';
3
4
  import { EventBody } from '@schematichq/schematic-js';
4
5
  import { EventBodyIdentify } from '@schematichq/schematic-js';
@@ -21,6 +22,8 @@ declare type BaseSchematicProviderProps = Omit<SchematicJS.SchematicOptions, "cl
21
22
 
22
23
  export { CheckFlagReturn }
23
24
 
25
+ export { CheckPlanReturn }
26
+
24
27
  export { Event_2 as Event }
25
28
 
26
29
  export { EventBody }
@@ -90,4 +93,10 @@ export declare type UseSchematicFlagOpts = SchematicHookOpts & {
90
93
 
91
94
  export declare const useSchematicIsPending: (opts?: SchematicHookOpts) => boolean;
92
95
 
96
+ export declare const useSchematicPlan: (opts?: UseSchematicPlanOpts) => SchematicJS.CheckPlanReturn | undefined;
97
+
98
+ export declare type UseSchematicPlanOpts = SchematicHookOpts & {
99
+ fallback?: SchematicJS.CheckPlanReturn;
100
+ };
101
+
93
102
  export { }
@@ -606,6 +606,36 @@ function v4(options, buf, offset) {
606
606
  }
607
607
  var v4_default = v4;
608
608
  var import_polyfill = __toESM(require_browser_polyfill());
609
+ function EntitlementValueTypeFromJSON(json) {
610
+ return EntitlementValueTypeFromJSONTyped(json, false);
611
+ }
612
+ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
613
+ return json;
614
+ }
615
+ function FeatureEntitlementFromJSON(json) {
616
+ return FeatureEntitlementFromJSONTyped(json, false);
617
+ }
618
+ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
619
+ if (json == null) {
620
+ return json;
621
+ }
622
+ return {
623
+ allocation: json["allocation"] == null ? void 0 : json["allocation"],
624
+ creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
625
+ creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
626
+ creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
627
+ creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
628
+ eventName: json["event_name"] == null ? void 0 : json["event_name"],
629
+ featureId: json["feature_id"],
630
+ featureKey: json["feature_key"],
631
+ metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
632
+ metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
633
+ monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
634
+ softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
635
+ usage: json["usage"] == null ? void 0 : json["usage"],
636
+ valueType: EntitlementValueTypeFromJSON(json["value_type"])
637
+ };
638
+ }
609
639
  function CheckFlagResponseDataFromJSON(json) {
610
640
  return CheckFlagResponseDataFromJSONTyped(json, false);
611
641
  }
@@ -615,6 +645,7 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
615
645
  }
616
646
  return {
617
647
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
648
+ entitlement: json["entitlement"] == null ? void 0 : FeatureEntitlementFromJSON(json["entitlement"]),
618
649
  error: json["error"] == null ? void 0 : json["error"],
619
650
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
620
651
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
@@ -630,26 +661,6 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
630
661
  value: json["value"]
631
662
  };
632
663
  }
633
- function EventBodyFlagCheckToJSON(json) {
634
- return EventBodyFlagCheckToJSONTyped(json, false);
635
- }
636
- function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
637
- if (value == null) {
638
- return value;
639
- }
640
- return {
641
- company_id: value["companyId"],
642
- error: value["error"],
643
- flag_id: value["flagId"],
644
- flag_key: value["flagKey"],
645
- reason: value["reason"],
646
- req_company: value["reqCompany"],
647
- req_user: value["reqUser"],
648
- rule_id: value["ruleId"],
649
- user_id: value["userId"],
650
- value: value["value"]
651
- };
652
- }
653
664
  function CheckFlagResponseFromJSON(json) {
654
665
  return CheckFlagResponseFromJSONTyped(json, false);
655
666
  }
@@ -662,6 +673,19 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
662
673
  params: json["params"]
663
674
  };
664
675
  }
676
+ function DatastreamCompanyPlanFromJSON(json) {
677
+ return DatastreamCompanyPlanFromJSONTyped(json, false);
678
+ }
679
+ function DatastreamCompanyPlanFromJSONTyped(json, ignoreDiscriminator) {
680
+ if (json == null) {
681
+ return json;
682
+ }
683
+ return {
684
+ id: json["id"],
685
+ name: json["name"],
686
+ trialEndDate: json["trial_end_date"] == null ? void 0 : new Date(json["trial_end_date"])
687
+ };
688
+ }
665
689
  function CheckFlagsResponseDataFromJSON(json) {
666
690
  return CheckFlagsResponseDataFromJSONTyped(json, false);
667
691
  }
@@ -670,7 +694,8 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
670
694
  return json;
671
695
  }
672
696
  return {
673
- flags: json["flags"].map(CheckFlagResponseDataFromJSON)
697
+ flags: json["flags"].map(CheckFlagResponseDataFromJSON),
698
+ plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
674
699
  };
675
700
  }
676
701
  function CheckFlagsResponseFromJSON(json) {
@@ -685,6 +710,26 @@ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
685
710
  params: json["params"]
686
711
  };
687
712
  }
713
+ function EventBodyFlagCheckToJSON(json) {
714
+ return EventBodyFlagCheckToJSONTyped(json, false);
715
+ }
716
+ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
717
+ if (value == null) {
718
+ return value;
719
+ }
720
+ return {
721
+ company_id: value["companyId"],
722
+ error: value["error"],
723
+ flag_id: value["flagId"],
724
+ flag_key: value["flagKey"],
725
+ reason: value["reason"],
726
+ req_company: value["reqCompany"],
727
+ req_user: value["reqUser"],
728
+ rule_id: value["ruleId"],
729
+ user_id: value["userId"],
730
+ value: value["value"]
731
+ };
732
+ }
688
733
  var RuleType = /* @__PURE__ */ ((RuleType2) => {
689
734
  RuleType2["GLOBAL_OVERRIDE"] = "global_override";
690
735
  RuleType2["COMPANY_OVERRIDE"] = "company_override";
@@ -740,6 +785,14 @@ var CheckFlagReturnFromJSON = (json) => {
740
785
  value
741
786
  };
742
787
  };
788
+ var CheckPlanReturnFromJSON = (json) => {
789
+ const { id, name, trialEndDate } = DatastreamCompanyPlanFromJSON(json);
790
+ return {
791
+ id,
792
+ name,
793
+ trialEndDate: trialEndDate == null ? void 0 : trialEndDate
794
+ };
795
+ };
743
796
  function contextString(context) {
744
797
  const sortedContext = Object.keys(context).reduce((acc, key) => {
745
798
  const sortedKeys = Object.keys(
@@ -754,7 +807,7 @@ function contextString(context) {
754
807
  }, {});
755
808
  return JSON.stringify(sortedContext);
756
809
  }
757
- var version = "1.2.17";
810
+ var version = "1.3.0";
758
811
  var anonymousIdKey = "schematicId";
759
812
  var Schematic = class {
760
813
  additionalHeaders = {};
@@ -771,10 +824,12 @@ var Schematic = class {
771
824
  flagValueListeners = {};
772
825
  isPending = true;
773
826
  isPendingListeners = /* @__PURE__ */ new Set();
827
+ planListeners = /* @__PURE__ */ new Set();
774
828
  storage;
775
829
  useWebSocket = false;
776
830
  checks = {};
777
831
  featureUsageEventMap = {};
832
+ planChecks = {};
778
833
  webSocketUrl = "wss://api.schematichq.com";
779
834
  webSocketConnectionTimeout = 1e4;
780
835
  webSocketReconnect = true;
@@ -800,6 +855,7 @@ var Schematic = class {
800
855
  retryTimer = null;
801
856
  flagValueDefaults = {};
802
857
  flagCheckDefaults = {};
858
+ fallbackCheckCache = {};
803
859
  constructor(apiKey, options) {
804
860
  this.apiKey = apiKey;
805
861
  this.eventQueue = [];
@@ -1059,6 +1115,13 @@ var Schematic = class {
1059
1115
  );
1060
1116
  if (typeof flagCheck !== "undefined") {
1061
1117
  this.submitFlagCheckEvent(key, flagCheck, context);
1118
+ } else {
1119
+ const fallbackResult = this.resolveFallbackCheckFlagReturn(
1120
+ key,
1121
+ fallback,
1122
+ "No flag values available"
1123
+ );
1124
+ this.submitFlagCheckEvent(key, fallbackResult, context);
1062
1125
  }
1063
1126
  return result;
1064
1127
  } catch (error) {
@@ -1099,28 +1162,32 @@ var Schematic = class {
1099
1162
  this.checks[contextStr] = {};
1100
1163
  }
1101
1164
  this.checks[contextStr][flagCheck.flag] = flagCheck;
1102
- this.debug(`WebSocket flag update:`, {
1103
- flag: flagCheck.flag,
1104
- value: flagCheck.value,
1105
- flagCheck
1106
- });
1107
1165
  if (typeof flagCheck.featureUsageEvent === "string") {
1108
1166
  this.updateFeatureUsageEventMap(flagCheck);
1109
1167
  }
1110
1168
  if ((this.flagCheckListeners[flag.flag]?.size ?? 0) > 0 || (this.flagValueListeners[flag.flag]?.size ?? 0) > 0) {
1111
1169
  this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
1112
1170
  }
1113
- this.debug(`About to notify listeners for flag ${flag.flag}`, {
1114
- flag: flag.flag,
1115
- value: flagCheck.value
1116
- });
1171
+ this.debug(
1172
+ `WebSocket flag update received. Notifying listeners for ${flag.flag}`,
1173
+ {
1174
+ flag: flag.flag,
1175
+ value: flagCheck.value,
1176
+ flagCheck
1177
+ }
1178
+ );
1117
1179
  this.notifyFlagCheckListeners(flag.flag, flagCheck);
1118
1180
  this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1119
- this.debug(`Finished notifying listeners for flag ${flag.flag}`, {
1120
- flag: flag.flag,
1121
- value: flagCheck.value
1122
- });
1123
1181
  });
1182
+ if (message.plan !== void 0 && message.plan !== null) {
1183
+ const plan = CheckPlanReturnFromJSON(message.plan);
1184
+ const contextStr = contextString(context);
1185
+ this.planChecks[contextStr] = plan;
1186
+ this.debug(`WebSocket plan update received. Notifying listeners`, {
1187
+ plan
1188
+ });
1189
+ this.notifyPlanListeners(plan);
1190
+ }
1124
1191
  this.flushContextDependentEventQueue();
1125
1192
  this.setIsPending(false);
1126
1193
  };
@@ -1224,6 +1291,9 @@ var Schematic = class {
1224
1291
  this.setIsPending(false);
1225
1292
  return Promise.resolve();
1226
1293
  }
1294
+ if (contextString(context) === contextString(this.context) && this.conn !== null && !this.isPending) {
1295
+ return;
1296
+ }
1227
1297
  try {
1228
1298
  this.setIsPending(true);
1229
1299
  if (!this.conn) {
@@ -1263,7 +1333,10 @@ var Schematic = class {
1263
1333
  await this.wsSendMessage(socket, context);
1264
1334
  } catch (error) {
1265
1335
  console.warn("Failed to establish WebSocket connection:", error);
1266
- throw error;
1336
+ this.context = context;
1337
+ this.flushContextDependentEventQueue();
1338
+ this.setIsPending(false);
1339
+ this.attemptReconnect();
1267
1340
  }
1268
1341
  };
1269
1342
  /**
@@ -2004,11 +2077,17 @@ var Schematic = class {
2004
2077
  };
2005
2078
  };
2006
2079
  setIsPending = (isPending) => {
2080
+ if (this.isPending === isPending) return;
2007
2081
  this.isPending = isPending;
2008
2082
  this.isPendingListeners.forEach(
2009
2083
  (listener) => notifyPendingListener(listener, isPending)
2010
2084
  );
2011
2085
  };
2086
+ getPlan = () => {
2087
+ const contextStr = contextString(this.context);
2088
+ const plan = this.planChecks[contextStr];
2089
+ return plan;
2090
+ };
2012
2091
  // flag checks state
2013
2092
  getFlagCheck = (flagKey) => {
2014
2093
  const contextStr = contextString(this.context);
@@ -2018,11 +2097,14 @@ var Schematic = class {
2018
2097
  return check;
2019
2098
  }
2020
2099
  if (flagKey in this.flagCheckDefaults || flagKey in this.flagValueDefaults) {
2021
- return this.resolveFallbackCheckFlagReturn(
2022
- flagKey,
2023
- void 0,
2024
- "Default value used"
2025
- );
2100
+ if (!(flagKey in this.fallbackCheckCache)) {
2101
+ this.fallbackCheckCache[flagKey] = this.resolveFallbackCheckFlagReturn(
2102
+ flagKey,
2103
+ void 0,
2104
+ "Default value used"
2105
+ );
2106
+ }
2107
+ return this.fallbackCheckCache[flagKey];
2026
2108
  }
2027
2109
  return void 0;
2028
2110
  };
@@ -2059,6 +2141,12 @@ var Schematic = class {
2059
2141
  this.flagCheckListeners[flagKey].delete(listener);
2060
2142
  };
2061
2143
  };
2144
+ addPlanListener = (listener) => {
2145
+ this.planListeners.add(listener);
2146
+ return () => {
2147
+ this.planListeners.delete(listener);
2148
+ };
2149
+ };
2062
2150
  notifyFlagCheckListeners = (flagKey, check) => {
2063
2151
  const listeners = this.flagCheckListeners?.[flagKey] ?? [];
2064
2152
  if (listeners.size > 0) {
@@ -2107,6 +2195,21 @@ var Schematic = class {
2107
2195
  });
2108
2196
  });
2109
2197
  };
2198
+ notifyPlanListeners = (value) => {
2199
+ const listeners = this.planListeners ?? [];
2200
+ if (listeners.size > 0) {
2201
+ this.debug(`Notifying ${listeners.size} plan listeners`, { value });
2202
+ }
2203
+ listeners.forEach((listener, index) => {
2204
+ this.debug(`Calling listener ${index} for plan`, {
2205
+ value
2206
+ });
2207
+ notifyPlanListener(listener, value);
2208
+ this.debug(`Listener ${index} for plan completed`, {
2209
+ value
2210
+ });
2211
+ });
2212
+ };
2110
2213
  };
2111
2214
  var notifyPendingListener = (listener, value) => {
2112
2215
  if (listener.length > 0) {
@@ -2129,12 +2232,19 @@ var notifyFlagValueListener = (listener, value) => {
2129
2232
  listener();
2130
2233
  }
2131
2234
  };
2235
+ var notifyPlanListener = (listener, value) => {
2236
+ if (listener.length > 0) {
2237
+ listener(value);
2238
+ } else {
2239
+ listener();
2240
+ }
2241
+ };
2132
2242
 
2133
2243
  // src/context/schematic.tsx
2134
2244
  import React, { createContext, useEffect, useMemo, useRef } from "react";
2135
2245
 
2136
2246
  // src/version.ts
2137
- var version2 = "1.2.17";
2247
+ var version2 = "1.3.0";
2138
2248
 
2139
2249
  // src/context/schematic.tsx
2140
2250
  import { jsx } from "react/jsx-runtime";
@@ -2255,6 +2365,23 @@ var useSchematicEntitlement = (key, opts) => {
2255
2365
  }, [client, key, fallbackCheck]);
2256
2366
  return useSyncExternalStore(subscribe, getSnapshot, () => fallbackCheck);
2257
2367
  };
2368
+ var useSchematicPlan = (opts) => {
2369
+ const client = useSchematicClient(opts);
2370
+ const fallback = opts?.fallback;
2371
+ const fallbackPlan = useMemo2(
2372
+ () => fallback,
2373
+ [fallback?.id, fallback?.name, fallback?.trialEndDate?.getTime()]
2374
+ );
2375
+ const subscribe = useCallback(
2376
+ (callback) => client.addPlanListener(callback),
2377
+ [client]
2378
+ );
2379
+ const getSnapshot = useCallback(() => {
2380
+ const plan = client.getPlan();
2381
+ return plan ?? fallbackPlan;
2382
+ }, [client, fallbackPlan]);
2383
+ return useSyncExternalStore(subscribe, getSnapshot, () => fallbackPlan);
2384
+ };
2258
2385
  var useSchematicIsPending = (opts) => {
2259
2386
  const client = useSchematicClient(opts);
2260
2387
  const subscribe = useCallback(
@@ -2274,7 +2401,8 @@ export {
2274
2401
  useSchematicEntitlement,
2275
2402
  useSchematicEvents,
2276
2403
  useSchematicFlag,
2277
- useSchematicIsPending
2404
+ useSchematicIsPending,
2405
+ useSchematicPlan
2278
2406
  };
2279
2407
  /*! Bundled license information:
2280
2408
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-react",
3
- "version": "1.2.17",
3
+ "version": "1.3.0",
4
4
  "main": "dist/schematic-react.cjs.js",
5
5
  "module": "dist/schematic-react.esm.js",
6
6
  "types": "dist/schematic-react.d.ts",
@@ -31,34 +31,39 @@
31
31
  "prepare": "husky"
32
32
  },
33
33
  "dependencies": {
34
- "@schematichq/schematic-js": "^1.2.17"
34
+ "@schematichq/schematic-js": "^1.3.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@eslint/js": "^10.0.1",
38
- "@microsoft/api-extractor": "^7.56.3",
38
+ "@microsoft/api-extractor": "^7.57.7",
39
39
  "@testing-library/dom": "^10.4.1",
40
40
  "@testing-library/jest-dom": "^6.9.1",
41
41
  "@testing-library/react": "^16.3.2",
42
42
  "@types/react": "^19.2.14",
43
43
  "@vitest/browser": "^4.0.18",
44
- "esbuild": "^0.27.3",
45
- "eslint": "^9.39.2",
44
+ "esbuild": "^0.27.4",
45
+ "eslint": "^10.0.3",
46
46
  "eslint-plugin-import": "^2.32.0",
47
47
  "eslint-plugin-react": "^7.37.5",
48
48
  "eslint-plugin-react-hooks": "^7.0.1",
49
- "globals": "^17.3.0",
50
- "happy-dom": "^20.6.1",
49
+ "globals": "^17.4.0",
50
+ "happy-dom": "^20.8.4",
51
51
  "husky": "^9.1.7",
52
- "jsdom": "^28.0.0",
52
+ "jsdom": "^29.0.0",
53
53
  "prettier": "^3.8.1",
54
54
  "react": "^19.2.4",
55
55
  "react-dom": "^19.2.4",
56
56
  "typescript": "^5.9.3",
57
- "typescript-eslint": "^8.55.0",
57
+ "typescript-eslint": "^8.57.1",
58
58
  "vitest": "^4.0.18"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "react": ">=18"
62
62
  },
63
+ "resolutions": {
64
+ "minimatch": ">=3.1.3",
65
+ "rollup": ">=4.59.0",
66
+ "undici": ">=7.24.0"
67
+ },
63
68
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
64
69
  }