@schematichq/schematic-js 1.2.1 → 1.2.3

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.
@@ -628,6 +628,7 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
628
628
  error: json["error"] == null ? void 0 : json["error"],
629
629
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
630
630
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
631
+ featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
631
632
  featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
632
633
  featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
633
634
  flag: json["flag"],
@@ -640,6 +641,28 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
640
641
  };
641
642
  }
642
643
 
644
+ // src/types/api/models/EventBodyFlagCheck.ts
645
+ function EventBodyFlagCheckToJSON(json) {
646
+ return EventBodyFlagCheckToJSONTyped(json, false);
647
+ }
648
+ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
649
+ if (value == null) {
650
+ return value;
651
+ }
652
+ return {
653
+ company_id: value["companyId"],
654
+ error: value["error"],
655
+ flag_id: value["flagId"],
656
+ flag_key: value["flagKey"],
657
+ reason: value["reason"],
658
+ req_company: value["reqCompany"],
659
+ req_user: value["reqUser"],
660
+ rule_id: value["ruleId"],
661
+ user_id: value["userId"],
662
+ value: value["value"]
663
+ };
664
+ }
665
+
643
666
  // src/types/api/models/CheckFlagResponse.ts
644
667
  function CheckFlagResponseFromJSON(json) {
645
668
  return CheckFlagResponseFromJSONTyped(json, false);
@@ -705,6 +728,7 @@ var CheckFlagReturnFromJSON = (json) => {
705
728
  error,
706
729
  featureAllocation,
707
730
  featureUsage,
731
+ featureUsageEvent,
708
732
  featureUsagePeriod,
709
733
  featureUsageResetAt,
710
734
  flag,
@@ -724,6 +748,7 @@ var CheckFlagReturnFromJSON = (json) => {
724
748
  error: error == null ? void 0 : error,
725
749
  featureAllocation: featureAllocation == null ? void 0 : featureAllocation,
726
750
  featureUsage: featureUsage == null ? void 0 : featureUsage,
751
+ featureUsageEvent: featureUsageEvent === null ? void 0 : featureUsageEvent,
727
752
  featureUsagePeriod: featureUsagePeriod == null ? void 0 : featureUsagePeriod,
728
753
  featureUsageResetAt: featureUsageResetAt == null ? void 0 : featureUsageResetAt,
729
754
  flag,
@@ -753,7 +778,7 @@ function contextString(context) {
753
778
  }
754
779
 
755
780
  // src/version.ts
756
- var version = "1.2.1";
781
+ var version = "1.2.3";
757
782
 
758
783
  // src/index.ts
759
784
  var anonymousIdKey = "schematicId";
@@ -763,6 +788,8 @@ var Schematic = class {
763
788
  apiUrl = "https://api.schematichq.com";
764
789
  conn = null;
765
790
  context = {};
791
+ debugEnabled = false;
792
+ offlineEnabled = false;
766
793
  eventQueue;
767
794
  eventUrl = "https://c.schematichq.com";
768
795
  flagCheckListeners = {};
@@ -772,11 +799,32 @@ var Schematic = class {
772
799
  storage;
773
800
  useWebSocket = false;
774
801
  checks = {};
802
+ featureUsageEventMap = {};
775
803
  webSocketUrl = "wss://api.schematichq.com";
776
804
  constructor(apiKey, options) {
777
805
  this.apiKey = apiKey;
778
806
  this.eventQueue = [];
779
807
  this.useWebSocket = options?.useWebSocket ?? false;
808
+ this.debugEnabled = options?.debug ?? false;
809
+ this.offlineEnabled = options?.offline ?? false;
810
+ if (typeof window !== "undefined" && typeof window.location !== "undefined") {
811
+ const params = new URLSearchParams(window.location.search);
812
+ const debugParam = params.get("schematic_debug");
813
+ if (debugParam !== null && (debugParam === "" || debugParam === "true" || debugParam === "1")) {
814
+ this.debugEnabled = true;
815
+ }
816
+ const offlineParam = params.get("schematic_offline");
817
+ if (offlineParam !== null && (offlineParam === "" || offlineParam === "true" || offlineParam === "1")) {
818
+ this.offlineEnabled = true;
819
+ this.debugEnabled = true;
820
+ }
821
+ }
822
+ if (this.offlineEnabled && options?.debug !== false) {
823
+ this.debugEnabled = true;
824
+ }
825
+ if (this.offlineEnabled) {
826
+ this.setIsPending(false);
827
+ }
780
828
  this.additionalHeaders = {
781
829
  "X-Schematic-Client-Version": `schematic-js@${version}`,
782
830
  ...options?.additionalHeaders ?? {}
@@ -800,6 +848,13 @@ var Schematic = class {
800
848
  this.flushEventQueue();
801
849
  });
802
850
  }
851
+ if (this.offlineEnabled) {
852
+ this.debug(
853
+ "Initialized with offline mode enabled - no network requests will be made"
854
+ );
855
+ } else if (this.debugEnabled) {
856
+ this.debug("Initialized with debug mode enabled");
857
+ }
803
858
  }
804
859
  /**
805
860
  * Get value for a single flag.
@@ -812,6 +867,14 @@ var Schematic = class {
812
867
  const { fallback = false, key } = options;
813
868
  const context = options.context || this.context;
814
869
  const contextStr = contextString(context);
870
+ this.debug(`checkFlag: ${key}`, { context, fallback });
871
+ if (this.isOffline()) {
872
+ this.debug(`checkFlag offline result: ${key}`, {
873
+ value: fallback,
874
+ offlineMode: true
875
+ });
876
+ return fallback;
877
+ }
815
878
  if (!this.useWebSocket) {
816
879
  const requestUrl = `${this.apiUrl}/flags/${key}/check`;
817
880
  return fetch(requestUrl, {
@@ -828,17 +891,35 @@ var Schematic = class {
828
891
  }
829
892
  return response.json();
830
893
  }).then((response) => {
831
- return CheckFlagResponseFromJSON(response).data.value;
894
+ const parsedResponse = CheckFlagResponseFromJSON(response);
895
+ this.debug(`checkFlag result: ${key}`, parsedResponse);
896
+ const result = CheckFlagReturnFromJSON(parsedResponse.data);
897
+ if (typeof result.featureUsageEvent === "string") {
898
+ this.updateFeatureUsageEventMap(result);
899
+ }
900
+ this.submitFlagCheckEvent(key, result, context);
901
+ return result.value;
832
902
  }).catch((error) => {
833
903
  console.error("There was a problem with the fetch operation:", error);
904
+ const errorResult = {
905
+ flag: key,
906
+ value: fallback,
907
+ reason: "API request failed",
908
+ error: error instanceof Error ? error.message : String(error)
909
+ };
910
+ this.submitFlagCheckEvent(key, errorResult, context);
834
911
  return fallback;
835
912
  });
836
913
  }
837
914
  try {
838
915
  const existingVals = this.checks[contextStr];
839
- if (this.conn && typeof existingVals !== "undefined" && typeof existingVals[key] !== "undefined") {
916
+ if (this.conn !== null && typeof existingVals !== "undefined" && typeof existingVals[key] !== "undefined") {
917
+ this.debug(`checkFlag cached result: ${key}`, existingVals[key]);
840
918
  return existingVals[key].value;
841
919
  }
920
+ if (this.isOffline()) {
921
+ return fallback;
922
+ }
842
923
  try {
843
924
  await this.setContext(context);
844
925
  } catch (error) {
@@ -849,16 +930,74 @@ var Schematic = class {
849
930
  return this.fallbackToRest(key, context, fallback);
850
931
  }
851
932
  const contextVals = this.checks[contextStr] ?? {};
852
- return contextVals[key]?.value ?? fallback;
933
+ const flagCheck = contextVals[key];
934
+ const result = flagCheck?.value ?? fallback;
935
+ this.debug(
936
+ `checkFlag WebSocket result: ${key}`,
937
+ typeof flagCheck !== "undefined" ? flagCheck : { value: fallback, fallbackUsed: true }
938
+ );
939
+ if (typeof flagCheck !== "undefined") {
940
+ this.submitFlagCheckEvent(key, flagCheck, context);
941
+ }
942
+ return result;
853
943
  } catch (error) {
854
944
  console.error("Unexpected error in checkFlag:", error);
945
+ const errorResult = {
946
+ flag: key,
947
+ value: fallback,
948
+ reason: "Unexpected error in flag check",
949
+ error: error instanceof Error ? error.message : String(error)
950
+ };
951
+ this.submitFlagCheckEvent(key, errorResult, context);
855
952
  return fallback;
856
953
  }
857
954
  }
955
+ /**
956
+ * Helper function to log debug messages
957
+ * Only logs if debug mode is enabled
958
+ */
959
+ debug(message, ...args) {
960
+ if (this.debugEnabled) {
961
+ console.log(`[Schematic] ${message}`, ...args);
962
+ }
963
+ }
964
+ /**
965
+ * Helper function to check if client is in offline mode
966
+ */
967
+ isOffline() {
968
+ return this.offlineEnabled;
969
+ }
970
+ /**
971
+ * Submit a flag check event
972
+ * Records data about a flag check for analytics
973
+ */
974
+ submitFlagCheckEvent(flagKey, result, context) {
975
+ const eventBody = {
976
+ flagKey,
977
+ value: result.value,
978
+ reason: result.reason,
979
+ flagId: result.flagId,
980
+ ruleId: result.ruleId,
981
+ companyId: result.companyId,
982
+ userId: result.userId,
983
+ error: result.error,
984
+ reqCompany: context.company,
985
+ reqUser: context.user
986
+ };
987
+ this.debug(`submitting flag check event:`, eventBody);
988
+ return this.handleEvent("flag_check", EventBodyFlagCheckToJSON(eventBody));
989
+ }
858
990
  /**
859
991
  * Helper method for falling back to REST API when WebSocket connection fails
860
992
  */
861
993
  async fallbackToRest(key, context, fallback) {
994
+ if (this.isOffline()) {
995
+ this.debug(`fallbackToRest offline result: ${key}`, {
996
+ value: fallback,
997
+ offlineMode: true
998
+ });
999
+ return fallback;
1000
+ }
862
1001
  try {
863
1002
  const requestUrl = `${this.apiUrl}/flags/${key}/check`;
864
1003
  const response = await fetch(requestUrl, {
@@ -873,19 +1012,39 @@ var Schematic = class {
873
1012
  if (!response.ok) {
874
1013
  throw new Error("Network response was not ok");
875
1014
  }
876
- const data = CheckFlagResponseFromJSON(await response.json());
877
- return data?.data?.value ?? false;
1015
+ const responseJson = await response.json();
1016
+ const data = CheckFlagResponseFromJSON(responseJson);
1017
+ this.debug(`fallbackToRest result: ${key}`, data);
1018
+ const result = CheckFlagReturnFromJSON(data.data);
1019
+ if (typeof result.featureUsageEvent === "string") {
1020
+ this.updateFeatureUsageEventMap(result);
1021
+ }
1022
+ this.submitFlagCheckEvent(key, result, context);
1023
+ return result.value;
878
1024
  } catch (error) {
879
1025
  console.error("REST API call failed, using fallback value:", error);
1026
+ const errorResult = {
1027
+ flag: key,
1028
+ value: fallback,
1029
+ reason: "API request failed (fallback)",
1030
+ error: error instanceof Error ? error.message : String(error)
1031
+ };
1032
+ this.submitFlagCheckEvent(key, errorResult, context);
880
1033
  return fallback;
881
1034
  }
882
1035
  }
883
1036
  /**
884
1037
  * Make an API call to fetch all flag values for a given context.
885
1038
  * Recommended for use in REST mode only.
1039
+ * In offline mode, returns an empty object.
886
1040
  */
887
1041
  checkFlags = async (context) => {
888
1042
  context = context || this.context;
1043
+ this.debug(`checkFlags`, { context });
1044
+ if (this.isOffline()) {
1045
+ this.debug(`checkFlags offline result: returning empty object`);
1046
+ return {};
1047
+ }
889
1048
  const requestUrl = `${this.apiUrl}/flags/check`;
890
1049
  const requestBody = JSON.stringify(context);
891
1050
  return fetch(requestUrl, {
@@ -903,6 +1062,7 @@ var Schematic = class {
903
1062
  return response.json();
904
1063
  }).then((responseJson) => {
905
1064
  const resp = CheckFlagsResponseFromJSON(responseJson);
1065
+ this.debug(`checkFlags result:`, resp);
906
1066
  return (resp?.data?.flags ?? []).reduce(
907
1067
  (accum, flag) => {
908
1068
  accum[flag.flag] = flag.value;
@@ -921,6 +1081,7 @@ var Schematic = class {
921
1081
  * send an identify event to the Schematic API which will upsert a user and company.
922
1082
  */
923
1083
  identify = (body) => {
1084
+ this.debug(`identify:`, body);
924
1085
  try {
925
1086
  this.setContext({
926
1087
  company: body.company?.keys,
@@ -938,10 +1099,12 @@ var Schematic = class {
938
1099
  * 2. Send the context to the server
939
1100
  * 3. Wait for initial flag values to be returned
940
1101
  * The promise resolves when initial flag values are received.
1102
+ * In offline mode, this will just set the context locally without connecting.
941
1103
  */
942
1104
  setContext = async (context) => {
943
- if (!this.useWebSocket) {
1105
+ if (this.isOffline() || !this.useWebSocket) {
944
1106
  this.context = context;
1107
+ this.setIsPending(false);
945
1108
  return Promise.resolve();
946
1109
  }
947
1110
  try {
@@ -959,14 +1122,67 @@ var Schematic = class {
959
1122
  /**
960
1123
  * Send a track event
961
1124
  * Track usage for a company and/or user.
1125
+ * Optimistically updates feature usage flags if tracking a featureUsageEvent.
962
1126
  */
963
1127
  track = (body) => {
964
- const { company, user, event, traits } = body;
965
- return this.handleEvent("track", {
1128
+ const { company, user, event, traits, quantity = 1 } = body;
1129
+ const trackData = {
966
1130
  company: company ?? this.context.company,
967
1131
  event,
968
1132
  traits: traits ?? {},
969
- user: user ?? this.context.user
1133
+ user: user ?? this.context.user,
1134
+ quantity
1135
+ };
1136
+ this.debug(`track:`, trackData);
1137
+ if (event in this.featureUsageEventMap) {
1138
+ this.optimisticallyUpdateFeatureUsage(event, quantity);
1139
+ }
1140
+ return this.handleEvent("track", trackData);
1141
+ };
1142
+ /**
1143
+ * Optimistically update feature usage flags associated with a tracked event
1144
+ * This updates flags in memory with updated usage counts and value/featureUsageExceeded flags
1145
+ * before the network request completes
1146
+ */
1147
+ optimisticallyUpdateFeatureUsage = (eventName, quantity = 1) => {
1148
+ const flagsForEvent = this.featureUsageEventMap[eventName];
1149
+ if (flagsForEvent === void 0 || flagsForEvent === null) return;
1150
+ this.debug(
1151
+ `Optimistically updating feature usage for event: ${eventName}`,
1152
+ { quantity }
1153
+ );
1154
+ Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
1155
+ if (check === void 0) return;
1156
+ const updatedCheck = { ...check };
1157
+ if (typeof updatedCheck.featureUsage === "number") {
1158
+ updatedCheck.featureUsage += quantity;
1159
+ if (typeof updatedCheck.featureAllocation === "number") {
1160
+ const wasExceeded = updatedCheck.featureUsageExceeded === true;
1161
+ const nowExceeded = updatedCheck.featureUsage >= updatedCheck.featureAllocation;
1162
+ if (nowExceeded !== wasExceeded) {
1163
+ updatedCheck.featureUsageExceeded = nowExceeded;
1164
+ if (nowExceeded) {
1165
+ updatedCheck.value = false;
1166
+ }
1167
+ this.debug(`Usage limit status changed for flag: ${flagKey}`, {
1168
+ was: wasExceeded ? "exceeded" : "within limits",
1169
+ now: nowExceeded ? "exceeded" : "within limits",
1170
+ featureUsage: updatedCheck.featureUsage,
1171
+ featureAllocation: updatedCheck.featureAllocation,
1172
+ value: updatedCheck.value
1173
+ });
1174
+ }
1175
+ }
1176
+ if (this.featureUsageEventMap[eventName] !== void 0) {
1177
+ this.featureUsageEventMap[eventName][flagKey] = updatedCheck;
1178
+ }
1179
+ const contextStr = contextString(this.context);
1180
+ if (this.checks[contextStr] !== void 0 && this.checks[contextStr] !== null) {
1181
+ this.checks[contextStr][flagKey] = updatedCheck;
1182
+ }
1183
+ this.notifyFlagCheckListeners(flagKey, updatedCheck);
1184
+ this.notifyFlagValueListeners(flagKey, updatedCheck.value);
1185
+ }
970
1186
  });
971
1187
  };
972
1188
  /**
@@ -1010,8 +1226,13 @@ var Schematic = class {
1010
1226
  sendEvent = async (event) => {
1011
1227
  const captureUrl = `${this.eventUrl}/e`;
1012
1228
  const payload = JSON.stringify(event);
1229
+ this.debug(`sending event:`, { url: captureUrl, event });
1230
+ if (this.isOffline()) {
1231
+ this.debug(`event not sent (offline mode):`, { event });
1232
+ return Promise.resolve();
1233
+ }
1013
1234
  try {
1014
- await fetch(captureUrl, {
1235
+ const response = await fetch(captureUrl, {
1015
1236
  method: "POST",
1016
1237
  headers: {
1017
1238
  ...this.additionalHeaders ?? {},
@@ -1019,6 +1240,10 @@ var Schematic = class {
1019
1240
  },
1020
1241
  body: payload
1021
1242
  });
1243
+ this.debug(`event sent:`, {
1244
+ status: response.status,
1245
+ statusText: response.statusText
1246
+ });
1022
1247
  } catch (error) {
1023
1248
  console.error("Error sending Schematic event: ", error);
1024
1249
  }
@@ -1033,8 +1258,13 @@ var Schematic = class {
1033
1258
  */
1034
1259
  /**
1035
1260
  * If using websocket mode, close the connection when done.
1261
+ * In offline mode, this is a no-op.
1036
1262
  */
1037
1263
  cleanup = async () => {
1264
+ if (this.isOffline()) {
1265
+ this.debug("cleanup: skipped (offline mode)");
1266
+ return Promise.resolve();
1267
+ }
1038
1268
  if (this.conn) {
1039
1269
  try {
1040
1270
  const socket = await this.conn;
@@ -1048,16 +1278,26 @@ var Schematic = class {
1048
1278
  };
1049
1279
  // Open a websocket connection
1050
1280
  wsConnect = () => {
1281
+ if (this.isOffline()) {
1282
+ this.debug("wsConnect: skipped (offline mode)");
1283
+ return Promise.reject(
1284
+ new Error("WebSocket connection skipped in offline mode")
1285
+ );
1286
+ }
1051
1287
  return new Promise((resolve, reject) => {
1052
1288
  const wsUrl = `${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;
1289
+ this.debug(`connecting to WebSocket:`, wsUrl);
1053
1290
  const webSocket = new WebSocket(wsUrl);
1054
1291
  webSocket.onopen = () => {
1292
+ this.debug(`WebSocket connection opened`);
1055
1293
  resolve(webSocket);
1056
1294
  };
1057
1295
  webSocket.onerror = (error) => {
1296
+ this.debug(`WebSocket connection error:`, error);
1058
1297
  reject(error);
1059
1298
  };
1060
1299
  webSocket.onclose = () => {
1300
+ this.debug(`WebSocket connection closed`);
1061
1301
  this.conn = null;
1062
1302
  };
1063
1303
  });
@@ -1065,21 +1305,44 @@ var Schematic = class {
1065
1305
  // Send a message on the websocket indicating interest in a particular evaluation context
1066
1306
  // and wait for the initial set of flag values to be returned
1067
1307
  wsSendMessage = (socket, context) => {
1308
+ if (this.isOffline()) {
1309
+ this.debug("wsSendMessage: skipped (offline mode)");
1310
+ this.setIsPending(false);
1311
+ return Promise.resolve();
1312
+ }
1068
1313
  return new Promise((resolve, reject) => {
1069
1314
  if (contextString(context) == contextString(this.context)) {
1315
+ this.debug(`WebSocket context unchanged, skipping update`);
1070
1316
  return resolve(this.setIsPending(false));
1071
1317
  }
1318
+ this.debug(`WebSocket context updated:`, context);
1072
1319
  this.context = context;
1073
1320
  const sendMessage = () => {
1074
1321
  let resolved = false;
1075
1322
  const messageHandler = (event) => {
1076
1323
  const message = JSON.parse(event.data);
1324
+ this.debug(`WebSocket message received:`, message);
1077
1325
  if (!(contextString(context) in this.checks)) {
1078
1326
  this.checks[contextString(context)] = {};
1079
1327
  }
1080
1328
  (message.flags ?? []).forEach((flag) => {
1081
1329
  const flagCheck = CheckFlagReturnFromJSON(flag);
1082
- this.checks[contextString(context)][flagCheck.flag] = flagCheck;
1330
+ const contextStr = contextString(context);
1331
+ if (this.checks[contextStr] === void 0) {
1332
+ this.checks[contextStr] = {};
1333
+ }
1334
+ this.checks[contextStr][flagCheck.flag] = flagCheck;
1335
+ this.debug(`WebSocket flag update:`, {
1336
+ flag: flagCheck.flag,
1337
+ value: flagCheck.value,
1338
+ flagCheck
1339
+ });
1340
+ if (typeof flagCheck.featureUsageEvent === "string") {
1341
+ this.updateFeatureUsageEventMap(flagCheck);
1342
+ }
1343
+ if (this.flagCheckListeners[flag.flag]?.size > 0 || this.flagValueListeners[flag.flag]?.size > 0) {
1344
+ this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
1345
+ }
1083
1346
  this.notifyFlagCheckListeners(flag.flag, flagCheck);
1084
1347
  this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1085
1348
  });
@@ -1090,19 +1353,23 @@ var Schematic = class {
1090
1353
  }
1091
1354
  };
1092
1355
  socket.addEventListener("message", messageHandler);
1093
- socket.send(
1094
- JSON.stringify({
1095
- apiKey: this.apiKey,
1096
- clientVersion: `schematic-js@${version}`,
1097
- data: context
1098
- })
1099
- );
1356
+ const clientVersion = this.additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
1357
+ const messagePayload = {
1358
+ apiKey: this.apiKey,
1359
+ clientVersion,
1360
+ data: context
1361
+ };
1362
+ this.debug(`WebSocket sending message:`, messagePayload);
1363
+ socket.send(JSON.stringify(messagePayload));
1100
1364
  };
1101
1365
  if (socket.readyState === WebSocket.OPEN) {
1366
+ this.debug(`WebSocket already open, sending message`);
1102
1367
  sendMessage();
1103
1368
  } else if (socket.readyState === WebSocket.CONNECTING) {
1369
+ this.debug(`WebSocket connecting, waiting for open to send message`);
1104
1370
  socket.addEventListener("open", sendMessage);
1105
1371
  } else {
1372
+ this.debug(`WebSocket is closed, cannot send message`);
1106
1373
  reject("WebSocket is not open or connecting");
1107
1374
  }
1108
1375
  });
@@ -1159,10 +1426,40 @@ var Schematic = class {
1159
1426
  };
1160
1427
  notifyFlagCheckListeners = (flagKey, check) => {
1161
1428
  const listeners = this.flagCheckListeners?.[flagKey] ?? [];
1429
+ if (listeners.size > 0) {
1430
+ this.debug(
1431
+ `Notifying ${listeners.size} flag check listeners for ${flagKey}`,
1432
+ check
1433
+ );
1434
+ }
1435
+ if (typeof check.featureUsageEvent === "string") {
1436
+ this.updateFeatureUsageEventMap(check);
1437
+ }
1162
1438
  listeners.forEach((listener) => notifyFlagCheckListener(listener, check));
1163
1439
  };
1440
+ /** Add or update a CheckFlagReturn in the featureUsageEventMap */
1441
+ updateFeatureUsageEventMap = (check) => {
1442
+ if (typeof check.featureUsageEvent !== "string") return;
1443
+ const eventName = check.featureUsageEvent;
1444
+ if (this.featureUsageEventMap[eventName] === void 0 || this.featureUsageEventMap[eventName] === null) {
1445
+ this.featureUsageEventMap[eventName] = {};
1446
+ }
1447
+ if (this.featureUsageEventMap[eventName] !== void 0) {
1448
+ this.featureUsageEventMap[eventName][check.flag] = check;
1449
+ }
1450
+ this.debug(
1451
+ `Updated featureUsageEventMap for event: ${eventName}, flag: ${check.flag}`,
1452
+ check
1453
+ );
1454
+ };
1164
1455
  notifyFlagValueListeners = (flagKey, value) => {
1165
1456
  const listeners = this.flagValueListeners?.[flagKey] ?? [];
1457
+ if (listeners.size > 0) {
1458
+ this.debug(
1459
+ `Notifying ${listeners.size} flag value listeners for ${flagKey}`,
1460
+ { value }
1461
+ );
1462
+ }
1166
1463
  listeners.forEach((listener) => notifyFlagValueListener(listener, value));
1167
1464
  };
1168
1465
  };
@@ -1191,6 +1488,7 @@ export {
1191
1488
  CheckFlagResponseFromJSON,
1192
1489
  CheckFlagReturnFromJSON,
1193
1490
  CheckFlagsResponseFromJSON,
1491
+ EventBodyFlagCheckToJSON,
1194
1492
  RuleType,
1195
1493
  Schematic,
1196
1494
  UsagePeriod
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-js",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "main": "dist/schematic.cjs.js",
5
5
  "module": "dist/schematic.esm.js",
6
6
  "types": "dist/schematic.d.ts",
@@ -33,23 +33,24 @@
33
33
  "uuid": "^11.0.5"
34
34
  },
35
35
  "devDependencies": {
36
- "@microsoft/api-extractor": "^7.49.2",
37
- "@openapitools/openapi-generator-cli": "^2.16.3",
36
+ "@eslint/js": "^9.24.0",
37
+ "@microsoft/api-extractor": "^7.52.2",
38
+ "@openapitools/openapi-generator-cli": "^2.18.4",
38
39
  "@types/jest": "^29.5.14",
39
40
  "@types/uuid": "^10.0.0",
40
- "@typescript-eslint/eslint-plugin": "^8.23.0",
41
- "@typescript-eslint/parser": "^8.23.0",
42
- "esbuild": "^0.24.2",
41
+ "esbuild": "^0.25.2",
43
42
  "esbuild-jest": "^0.5.0",
44
- "eslint": "^8.57.1",
43
+ "eslint": "^9.24.0",
44
+ "globals": "^16.0.0",
45
45
  "jest": "^29.7.0",
46
46
  "jest-environment-jsdom": "^29.7.0",
47
47
  "jest-esbuild": "^0.3.0",
48
48
  "jest-fetch-mock": "^3.0.3",
49
49
  "mock-socket": "^9.3.1",
50
50
  "prettier": "^3.4.2",
51
- "ts-jest": "^29.2.5",
52
- "typescript": "^5.7.3"
51
+ "ts-jest": "^29.3.0",
52
+ "typescript": "^5.7.3",
53
+ "typescript-eslint": "^8.29.1"
53
54
  },
54
55
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
55
56
  }