@schematichq/schematic-vue 1.4.1 → 1.6.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.
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  useSchematic: () => useSchematic,
28
28
  useSchematicClient: () => useSchematicClient,
29
29
  useSchematicContext: () => useSchematicContext,
30
+ useSchematicCreditBalance: () => useSchematicCreditBalance,
30
31
  useSchematicEntitlement: () => useSchematicEntitlement,
31
32
  useSchematicEvents: () => useSchematicEvents,
32
33
  useSchematicFlag: () => useSchematicFlag,
@@ -35,7 +36,7 @@ __export(index_exports, {
35
36
  });
36
37
  module.exports = __toCommonJS(index_exports);
37
38
 
38
- // node_modules/@schematichq/schematic-js/dist/schematic.esm.js
39
+ // node_modules/.pnpm/@schematichq+schematic-js@1.8.0/node_modules/@schematichq/schematic-js/dist/schematic.esm.js
39
40
  var __create = Object.create;
40
41
  var __defProp2 = Object.defineProperty;
41
42
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -43,7 +44,15 @@ var __getOwnPropNames2 = Object.getOwnPropertyNames;
43
44
  var __getProtoOf = Object.getPrototypeOf;
44
45
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
45
46
  var __commonJS = (cb, mod) => function __require() {
46
- return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
47
+ try {
48
+ return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
49
+ } catch (e) {
50
+ throw mod = 0, e;
51
+ }
52
+ };
53
+ var __export2 = (target, all) => {
54
+ for (var name in all)
55
+ __defProp2(target, name, { get: all[name], enumerable: true });
47
56
  };
48
57
  var __copyProps2 = (to, from, except, desc) => {
49
58
  if (from && typeof from === "object" || typeof from === "function") {
@@ -62,7 +71,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
62
71
  mod
63
72
  ));
64
73
  var require_browser_polyfill = __commonJS({
65
- "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
74
+ "node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
66
75
  (function(self2) {
67
76
  var irrelevant = (function(exports2) {
68
77
  var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
@@ -602,19 +611,16 @@ for (let i = 0; i < 256; ++i) {
602
611
  function unsafeStringify(arr, offset = 0) {
603
612
  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();
604
613
  }
605
- var getRandomValues;
606
614
  var rnds8 = new Uint8Array(16);
607
615
  function rng() {
608
- if (!getRandomValues) {
609
- if (typeof crypto === "undefined" || !crypto.getRandomValues) {
610
- throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
611
- }
612
- getRandomValues = crypto.getRandomValues.bind(crypto);
616
+ return crypto.getRandomValues(rnds8);
617
+ }
618
+ function v4(options, buf, offset) {
619
+ if (!buf && !options && crypto.randomUUID) {
620
+ return crypto.randomUUID();
613
621
  }
614
- return getRandomValues(rnds8);
622
+ return _v4(options, buf, offset);
615
623
  }
616
- var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
617
- var native_default = { randomUUID };
618
624
  function _v4(options, buf, offset) {
619
625
  options = options || {};
620
626
  const rnds = options.random ?? options.rng?.() ?? rng();
@@ -635,12 +641,6 @@ function _v4(options, buf, offset) {
635
641
  }
636
642
  return unsafeStringify(rnds);
637
643
  }
638
- function v4(options, buf, offset) {
639
- if (native_default.randomUUID && !buf && !options) {
640
- return native_default.randomUUID();
641
- }
642
- return _v4(options, buf, offset);
643
- }
644
644
  var v4_default = v4;
645
645
  var import_polyfill = __toESM(require_browser_polyfill());
646
646
  function EntitlementValueTypeFromJSON(json) {
@@ -649,6 +649,30 @@ function EntitlementValueTypeFromJSON(json) {
649
649
  function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
650
650
  return json;
651
651
  }
652
+ function MetricPeriodMonthResetFromJSON(json) {
653
+ return MetricPeriodMonthResetFromJSONTyped(json, false);
654
+ }
655
+ function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
656
+ return json;
657
+ }
658
+ function WarningTierFromJSON(json) {
659
+ return WarningTierFromJSONTyped(json, false);
660
+ }
661
+ function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
662
+ if (json == null) {
663
+ return json;
664
+ }
665
+ return {
666
+ key: json["key"],
667
+ value: json["value"]
668
+ };
669
+ }
670
+ function MetricPeriodFromJSON(json) {
671
+ return MetricPeriodFromJSONTyped(json, false);
672
+ }
673
+ function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
674
+ return json;
675
+ }
652
676
  function FeatureEntitlementFromJSON(json) {
653
677
  return FeatureEntitlementFromJSONTyped(json, false);
654
678
  }
@@ -658,21 +682,32 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
658
682
  }
659
683
  return {
660
684
  allocation: json["allocation"] == null ? void 0 : json["allocation"],
685
+ consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
661
686
  creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
662
687
  creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
688
+ creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
689
+ creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
663
690
  creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
664
691
  creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
665
692
  eventName: json["event_name"] == null ? void 0 : json["event_name"],
693
+ eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
666
694
  featureId: json["feature_id"],
667
695
  featureKey: json["feature_key"],
668
- metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
696
+ metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
669
697
  metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
670
- monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
698
+ monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
671
699
  softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
672
700
  usage: json["usage"] == null ? void 0 : json["usage"],
673
- valueType: EntitlementValueTypeFromJSON(json["value_type"])
701
+ valueType: EntitlementValueTypeFromJSON(json["value_type"]),
702
+ warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
674
703
  };
675
704
  }
705
+ function RuleTypeFromJSON(json) {
706
+ return RuleTypeFromJSONTyped(json, false);
707
+ }
708
+ function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
709
+ return json;
710
+ }
676
711
  function CheckFlagResponseDataFromJSON(json) {
677
712
  return CheckFlagResponseDataFromJSONTyped(json, false);
678
713
  }
@@ -687,13 +722,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
687
722
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
688
723
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
689
724
  featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
690
- featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
725
+ featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
691
726
  featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
692
727
  flag: json["flag"],
693
728
  flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
694
729
  reason: json["reason"],
695
730
  ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
696
- ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
731
+ ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
697
732
  userId: json["user_id"] == null ? void 0 : json["user_id"],
698
733
  value: json["value"]
699
734
  };
@@ -710,6 +745,268 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
710
745
  params: json["params"]
711
746
  };
712
747
  }
748
+ var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
749
+ var Configuration = class {
750
+ constructor(configuration = {}) {
751
+ this.configuration = configuration;
752
+ }
753
+ configuration;
754
+ set config(configuration) {
755
+ this.configuration = configuration;
756
+ }
757
+ get basePath() {
758
+ return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
759
+ }
760
+ get fetchApi() {
761
+ return this.configuration.fetchApi;
762
+ }
763
+ get middleware() {
764
+ return this.configuration.middleware || [];
765
+ }
766
+ get queryParamsStringify() {
767
+ return this.configuration.queryParamsStringify || querystring;
768
+ }
769
+ get username() {
770
+ return this.configuration.username;
771
+ }
772
+ get password() {
773
+ return this.configuration.password;
774
+ }
775
+ get apiKey() {
776
+ const apiKey = this.configuration.apiKey;
777
+ if (apiKey) {
778
+ return typeof apiKey === "function" ? apiKey : () => apiKey;
779
+ }
780
+ return void 0;
781
+ }
782
+ get accessToken() {
783
+ const accessToken = this.configuration.accessToken;
784
+ if (accessToken) {
785
+ return typeof accessToken === "function" ? accessToken : async () => accessToken;
786
+ }
787
+ return void 0;
788
+ }
789
+ get headers() {
790
+ return this.configuration.headers;
791
+ }
792
+ get credentials() {
793
+ return this.configuration.credentials;
794
+ }
795
+ };
796
+ var DefaultConfig = new Configuration();
797
+ var BaseAPI = class _BaseAPI {
798
+ constructor(configuration = DefaultConfig) {
799
+ this.configuration = configuration;
800
+ this.middleware = configuration.middleware;
801
+ }
802
+ configuration;
803
+ static jsonRegex = new RegExp(
804
+ "^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
805
+ "i"
806
+ );
807
+ middleware;
808
+ withMiddleware(...middlewares) {
809
+ const next = this.clone();
810
+ next.middleware = next.middleware.concat(...middlewares);
811
+ return next;
812
+ }
813
+ withPreMiddleware(...preMiddlewares) {
814
+ const middlewares = preMiddlewares.map((pre) => ({ pre }));
815
+ return this.withMiddleware(...middlewares);
816
+ }
817
+ withPostMiddleware(...postMiddlewares) {
818
+ const middlewares = postMiddlewares.map((post) => ({ post }));
819
+ return this.withMiddleware(...middlewares);
820
+ }
821
+ /**
822
+ * Check if the given MIME is a JSON MIME.
823
+ * JSON MIME examples:
824
+ * application/json
825
+ * application/json; charset=UTF8
826
+ * APPLICATION/JSON
827
+ * application/vnd.company+json
828
+ * @param mime - MIME (Multipurpose Internet Mail Extensions)
829
+ * @return True if the given MIME is JSON, false otherwise.
830
+ */
831
+ isJsonMime(mime) {
832
+ if (!mime) {
833
+ return false;
834
+ }
835
+ return _BaseAPI.jsonRegex.test(mime);
836
+ }
837
+ async request(context, initOverrides) {
838
+ const { url, init } = await this.createFetchParams(context, initOverrides);
839
+ const response = await this.fetchApi(url, init);
840
+ if (response && response.status >= 200 && response.status < 300) {
841
+ return response;
842
+ }
843
+ throw new ResponseError(response, "Response returned an error code");
844
+ }
845
+ async createFetchParams(context, initOverrides) {
846
+ let url = this.configuration.basePath + context.path;
847
+ if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
848
+ url += "?" + this.configuration.queryParamsStringify(context.query);
849
+ }
850
+ const headers = Object.assign(
851
+ {},
852
+ this.configuration.headers,
853
+ context.headers
854
+ );
855
+ Object.keys(headers).forEach(
856
+ (key) => headers[key] === void 0 ? delete headers[key] : {}
857
+ );
858
+ const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
859
+ const initParams = {
860
+ method: context.method,
861
+ headers,
862
+ body: context.body,
863
+ credentials: this.configuration.credentials
864
+ };
865
+ const overriddenInit = {
866
+ ...initParams,
867
+ ...await initOverrideFn({
868
+ init: initParams,
869
+ context
870
+ })
871
+ };
872
+ let body;
873
+ if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
874
+ body = overriddenInit.body;
875
+ } else if (this.isJsonMime(headers["Content-Type"])) {
876
+ body = JSON.stringify(overriddenInit.body);
877
+ } else {
878
+ body = overriddenInit.body;
879
+ }
880
+ const init = {
881
+ ...overriddenInit,
882
+ body
883
+ };
884
+ return { url, init };
885
+ }
886
+ fetchApi = async (url, init) => {
887
+ let fetchParams = { url, init };
888
+ for (const middleware of this.middleware) {
889
+ if (middleware.pre) {
890
+ fetchParams = await middleware.pre({
891
+ fetch: this.fetchApi,
892
+ ...fetchParams
893
+ }) || fetchParams;
894
+ }
895
+ }
896
+ let response = void 0;
897
+ try {
898
+ response = await (this.configuration.fetchApi || fetch)(
899
+ fetchParams.url,
900
+ fetchParams.init
901
+ );
902
+ } catch (e) {
903
+ for (const middleware of this.middleware) {
904
+ if (middleware.onError) {
905
+ response = await middleware.onError({
906
+ fetch: this.fetchApi,
907
+ url: fetchParams.url,
908
+ init: fetchParams.init,
909
+ error: e,
910
+ response: response ? response.clone() : void 0
911
+ }) || response;
912
+ }
913
+ }
914
+ if (response === void 0) {
915
+ if (e instanceof Error) {
916
+ throw new FetchError(
917
+ e,
918
+ "The request failed and the interceptors did not return an alternative response"
919
+ );
920
+ } else {
921
+ throw e;
922
+ }
923
+ }
924
+ }
925
+ for (const middleware of this.middleware) {
926
+ if (middleware.post) {
927
+ response = await middleware.post({
928
+ fetch: this.fetchApi,
929
+ url: fetchParams.url,
930
+ init: fetchParams.init,
931
+ response: response.clone()
932
+ }) || response;
933
+ }
934
+ }
935
+ return response;
936
+ };
937
+ /**
938
+ * Create a shallow clone of `this` by constructing a new instance
939
+ * and then shallow cloning data members.
940
+ */
941
+ clone() {
942
+ const constructor = this.constructor;
943
+ const next = new constructor(this.configuration);
944
+ next.middleware = this.middleware.slice();
945
+ return next;
946
+ }
947
+ };
948
+ function isBlob(value) {
949
+ return typeof Blob !== "undefined" && value instanceof Blob;
950
+ }
951
+ function isFormData(value) {
952
+ return typeof FormData !== "undefined" && value instanceof FormData;
953
+ }
954
+ var ResponseError = class extends Error {
955
+ constructor(response, msg) {
956
+ super(msg);
957
+ this.response = response;
958
+ }
959
+ response;
960
+ name = "ResponseError";
961
+ };
962
+ var FetchError = class extends Error {
963
+ constructor(cause, msg) {
964
+ super(msg);
965
+ this.cause = cause;
966
+ }
967
+ cause;
968
+ name = "FetchError";
969
+ };
970
+ function querystring(params, prefix = "") {
971
+ return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
972
+ }
973
+ function querystringSingleKey(key, value, keyPrefix = "") {
974
+ const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
975
+ if (value instanceof Array) {
976
+ const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
977
+ return `${encodeURIComponent(fullKey)}=${multiValue}`;
978
+ }
979
+ if (value instanceof Set) {
980
+ const valueAsArray = Array.from(value);
981
+ return querystringSingleKey(key, valueAsArray, keyPrefix);
982
+ }
983
+ if (value instanceof Date) {
984
+ return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
985
+ }
986
+ if (value instanceof Object) {
987
+ return querystring(value, fullKey);
988
+ }
989
+ return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
990
+ }
991
+ function mapValues(data, fn) {
992
+ return Object.keys(data).reduce(
993
+ (acc, key) => ({ ...acc, [key]: fn(data[key]) }),
994
+ {}
995
+ );
996
+ }
997
+ function CompanyCreditBalanceFromJSON(json) {
998
+ return CompanyCreditBalanceFromJSONTyped(json, false);
999
+ }
1000
+ function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
1001
+ if (json == null) {
1002
+ return json;
1003
+ }
1004
+ return {
1005
+ remaining: json["remaining"],
1006
+ reserved: json["reserved"],
1007
+ settled: json["settled"]
1008
+ };
1009
+ }
713
1010
  function TrialStatusFromJSON(json) {
714
1011
  return TrialStatusFromJSONTyped(json, false);
715
1012
  }
@@ -738,6 +1035,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
738
1035
  return json;
739
1036
  }
740
1037
  return {
1038
+ creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
741
1039
  flags: json["flags"].map(CheckFlagResponseDataFromJSON),
742
1040
  plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
743
1041
  };
@@ -766,6 +1064,7 @@ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
766
1064
  error: value["error"],
767
1065
  flag_id: value["flagId"],
768
1066
  flag_key: value["flagKey"],
1067
+ preflight: value["preflight"],
769
1068
  reason: value["reason"],
770
1069
  req_company: value["reqCompany"],
771
1070
  req_user: value["reqUser"],
@@ -820,7 +1119,10 @@ var CheckFlagReturnFromJSON = (json) => {
820
1119
  return {
821
1120
  featureUsageExceeded,
822
1121
  companyId: companyId == null ? void 0 : companyId,
1122
+ creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
823
1123
  creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
1124
+ creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
1125
+ creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
824
1126
  error: error == null ? void 0 : error,
825
1127
  featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
826
1128
  featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
@@ -834,7 +1136,8 @@ var CheckFlagReturnFromJSON = (json) => {
834
1136
  ruleType: ruleType == null ? void 0 : ruleType,
835
1137
  softLimit: entitlement?.softLimit == null ? void 0 : entitlement.softLimit,
836
1138
  userId: userId == null ? void 0 : userId,
837
- value
1139
+ value,
1140
+ warningTiers: entitlement?.warningTiers == null ? void 0 : entitlement.warningTiers
838
1141
  };
839
1142
  };
840
1143
  var CheckPlanReturnFromJSON = (json) => {
@@ -846,6 +1149,22 @@ var CheckPlanReturnFromJSON = (json) => {
846
1149
  trialStatus: trialStatus == null ? void 0 : trialStatus
847
1150
  };
848
1151
  };
1152
+ var CreditBalancesFromJSON = (json) => {
1153
+ if (json == null || typeof json !== "object") {
1154
+ return {};
1155
+ }
1156
+ const balances = {};
1157
+ for (const [creditId, raw] of Object.entries(json)) {
1158
+ if (raw == null || typeof raw !== "object") continue;
1159
+ const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
1160
+ if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
1161
+ continue;
1162
+ }
1163
+ balances[creditId] = { remaining, reserved, settled };
1164
+ }
1165
+ return balances;
1166
+ };
1167
+ var cacheVersion = "7b920cf4";
849
1168
  function contextString(context) {
850
1169
  const sortedContext = Object.keys(context).reduce((acc, key) => {
851
1170
  const sortedKeys = Object.keys(
@@ -860,12 +1179,370 @@ function contextString(context) {
860
1179
  }, {});
861
1180
  return JSON.stringify(sortedContext);
862
1181
  }
863
- var version = "1.4.0";
1182
+ var version = "1.8.0";
1183
+ var models_exports = {};
1184
+ __export2(models_exports, {
1185
+ ApiErrorFromJSON: () => ApiErrorFromJSON,
1186
+ ApiErrorFromJSONTyped: () => ApiErrorFromJSONTyped,
1187
+ ApiErrorToJSON: () => ApiErrorToJSON,
1188
+ ApiErrorToJSONTyped: () => ApiErrorToJSONTyped,
1189
+ CompanyDiscountResponseDataFromJSON: () => CompanyDiscountResponseDataFromJSON,
1190
+ CompanyDiscountResponseDataFromJSONTyped: () => CompanyDiscountResponseDataFromJSONTyped,
1191
+ CompanyDiscountResponseDataToJSON: () => CompanyDiscountResponseDataToJSON,
1192
+ CompanyDiscountResponseDataToJSONTyped: () => CompanyDiscountResponseDataToJSONTyped,
1193
+ CompanyInvoiceResponseDataFromJSON: () => CompanyInvoiceResponseDataFromJSON,
1194
+ CompanyInvoiceResponseDataFromJSONTyped: () => CompanyInvoiceResponseDataFromJSONTyped,
1195
+ CompanyInvoiceResponseDataToJSON: () => CompanyInvoiceResponseDataToJSON,
1196
+ CompanyInvoiceResponseDataToJSONTyped: () => CompanyInvoiceResponseDataToJSONTyped,
1197
+ CompanyInvoicesResponseDataFromJSON: () => CompanyInvoicesResponseDataFromJSON,
1198
+ CompanyInvoicesResponseDataFromJSONTyped: () => CompanyInvoicesResponseDataFromJSONTyped,
1199
+ CompanyInvoicesResponseDataToJSON: () => CompanyInvoicesResponseDataToJSON,
1200
+ CompanyInvoicesResponseDataToJSONTyped: () => CompanyInvoicesResponseDataToJSONTyped,
1201
+ CompanyUpcomingInvoiceResponseDataFromJSON: () => CompanyUpcomingInvoiceResponseDataFromJSON,
1202
+ CompanyUpcomingInvoiceResponseDataFromJSONTyped: () => CompanyUpcomingInvoiceResponseDataFromJSONTyped,
1203
+ CompanyUpcomingInvoiceResponseDataToJSON: () => CompanyUpcomingInvoiceResponseDataToJSON,
1204
+ CompanyUpcomingInvoiceResponseDataToJSONTyped: () => CompanyUpcomingInvoiceResponseDataToJSONTyped,
1205
+ GetCompanyInvoicesParamsFromJSON: () => GetCompanyInvoicesParamsFromJSON,
1206
+ GetCompanyInvoicesParamsFromJSONTyped: () => GetCompanyInvoicesParamsFromJSONTyped,
1207
+ GetCompanyInvoicesParamsToJSON: () => GetCompanyInvoicesParamsToJSON,
1208
+ GetCompanyInvoicesParamsToJSONTyped: () => GetCompanyInvoicesParamsToJSONTyped,
1209
+ GetCompanyInvoicesResponseFromJSON: () => GetCompanyInvoicesResponseFromJSON,
1210
+ GetCompanyInvoicesResponseFromJSONTyped: () => GetCompanyInvoicesResponseFromJSONTyped,
1211
+ GetCompanyInvoicesResponseToJSON: () => GetCompanyInvoicesResponseToJSON,
1212
+ GetCompanyInvoicesResponseToJSONTyped: () => GetCompanyInvoicesResponseToJSONTyped,
1213
+ GetCompanyUpcomingInvoiceResponseFromJSON: () => GetCompanyUpcomingInvoiceResponseFromJSON,
1214
+ GetCompanyUpcomingInvoiceResponseFromJSONTyped: () => GetCompanyUpcomingInvoiceResponseFromJSONTyped,
1215
+ GetCompanyUpcomingInvoiceResponseToJSON: () => GetCompanyUpcomingInvoiceResponseToJSON,
1216
+ GetCompanyUpcomingInvoiceResponseToJSONTyped: () => GetCompanyUpcomingInvoiceResponseToJSONTyped,
1217
+ InvoiceStatus: () => InvoiceStatus,
1218
+ InvoiceStatusFromJSON: () => InvoiceStatusFromJSON,
1219
+ InvoiceStatusFromJSONTyped: () => InvoiceStatusFromJSONTyped,
1220
+ InvoiceStatusToJSON: () => InvoiceStatusToJSON,
1221
+ InvoiceStatusToJSONTyped: () => InvoiceStatusToJSONTyped,
1222
+ instanceOfApiError: () => instanceOfApiError,
1223
+ instanceOfCompanyDiscountResponseData: () => instanceOfCompanyDiscountResponseData,
1224
+ instanceOfCompanyInvoiceResponseData: () => instanceOfCompanyInvoiceResponseData,
1225
+ instanceOfCompanyInvoicesResponseData: () => instanceOfCompanyInvoicesResponseData,
1226
+ instanceOfCompanyUpcomingInvoiceResponseData: () => instanceOfCompanyUpcomingInvoiceResponseData,
1227
+ instanceOfGetCompanyInvoicesParams: () => instanceOfGetCompanyInvoicesParams,
1228
+ instanceOfGetCompanyInvoicesResponse: () => instanceOfGetCompanyInvoicesResponse,
1229
+ instanceOfGetCompanyUpcomingInvoiceResponse: () => instanceOfGetCompanyUpcomingInvoiceResponse,
1230
+ instanceOfInvoiceStatus: () => instanceOfInvoiceStatus
1231
+ });
1232
+ function instanceOfApiError(value) {
1233
+ if (!("error" in value) || value["error"] === void 0) return false;
1234
+ return true;
1235
+ }
1236
+ function ApiErrorFromJSON(json) {
1237
+ return ApiErrorFromJSONTyped(json, false);
1238
+ }
1239
+ function ApiErrorFromJSONTyped(json, ignoreDiscriminator) {
1240
+ if (json == null) {
1241
+ return json;
1242
+ }
1243
+ return {
1244
+ error: json["error"]
1245
+ };
1246
+ }
1247
+ function ApiErrorToJSON(json) {
1248
+ return ApiErrorToJSONTyped(json, false);
1249
+ }
1250
+ function ApiErrorToJSONTyped(value, ignoreDiscriminator = false) {
1251
+ if (value == null) {
1252
+ return value;
1253
+ }
1254
+ return {
1255
+ error: value["error"]
1256
+ };
1257
+ }
1258
+ function instanceOfCompanyDiscountResponseData(value) {
1259
+ if (!("couponName" in value) || value["couponName"] === void 0)
1260
+ return false;
1261
+ if (!("duration" in value) || value["duration"] === void 0) return false;
1262
+ return true;
1263
+ }
1264
+ function CompanyDiscountResponseDataFromJSON(json) {
1265
+ return CompanyDiscountResponseDataFromJSONTyped(json, false);
1266
+ }
1267
+ function CompanyDiscountResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1268
+ if (json == null) {
1269
+ return json;
1270
+ }
1271
+ return {
1272
+ amountOff: json["amount_off"] == null ? void 0 : json["amount_off"],
1273
+ couponName: json["coupon_name"],
1274
+ currency: json["currency"] == null ? void 0 : json["currency"],
1275
+ customerFacingCode: json["customer_facing_code"] == null ? void 0 : json["customer_facing_code"],
1276
+ duration: json["duration"],
1277
+ durationInMonths: json["duration_in_months"] == null ? void 0 : json["duration_in_months"],
1278
+ percentOff: json["percent_off"] == null ? void 0 : json["percent_off"]
1279
+ };
1280
+ }
1281
+ function CompanyDiscountResponseDataToJSON(json) {
1282
+ return CompanyDiscountResponseDataToJSONTyped(json, false);
1283
+ }
1284
+ function CompanyDiscountResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1285
+ if (value == null) {
1286
+ return value;
1287
+ }
1288
+ return {
1289
+ amount_off: value["amountOff"],
1290
+ coupon_name: value["couponName"],
1291
+ currency: value["currency"],
1292
+ customer_facing_code: value["customerFacingCode"],
1293
+ duration: value["duration"],
1294
+ duration_in_months: value["durationInMonths"],
1295
+ percent_off: value["percentOff"]
1296
+ };
1297
+ }
1298
+ var InvoiceStatus = {
1299
+ Draft: "draft",
1300
+ Open: "open",
1301
+ Paid: "paid",
1302
+ Uncollectible: "uncollectible",
1303
+ Void: "void"
1304
+ };
1305
+ function instanceOfInvoiceStatus(value) {
1306
+ for (const key in InvoiceStatus) {
1307
+ if (Object.prototype.hasOwnProperty.call(InvoiceStatus, key)) {
1308
+ if (InvoiceStatus[key] === value) {
1309
+ return true;
1310
+ }
1311
+ }
1312
+ }
1313
+ return false;
1314
+ }
1315
+ function InvoiceStatusFromJSON(json) {
1316
+ return InvoiceStatusFromJSONTyped(json, false);
1317
+ }
1318
+ function InvoiceStatusFromJSONTyped(json, ignoreDiscriminator) {
1319
+ return json;
1320
+ }
1321
+ function InvoiceStatusToJSON(value) {
1322
+ return value;
1323
+ }
1324
+ function InvoiceStatusToJSONTyped(value, ignoreDiscriminator) {
1325
+ return value;
1326
+ }
1327
+ function instanceOfCompanyInvoiceResponseData(value) {
1328
+ if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
1329
+ if (!("createdAt" in value) || value["createdAt"] === void 0) return false;
1330
+ if (!("currency" in value) || value["currency"] === void 0) return false;
1331
+ if (!("id" in value) || value["id"] === void 0) return false;
1332
+ return true;
1333
+ }
1334
+ function CompanyInvoiceResponseDataFromJSON(json) {
1335
+ return CompanyInvoiceResponseDataFromJSONTyped(json, false);
1336
+ }
1337
+ function CompanyInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1338
+ if (json == null) {
1339
+ return json;
1340
+ }
1341
+ return {
1342
+ amountDue: json["amount_due"],
1343
+ createdAt: new Date(json["created_at"]),
1344
+ currency: json["currency"],
1345
+ dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
1346
+ id: json["id"],
1347
+ status: json["status"] == null ? void 0 : InvoiceStatusFromJSON(json["status"]),
1348
+ url: json["url"] == null ? void 0 : json["url"]
1349
+ };
1350
+ }
1351
+ function CompanyInvoiceResponseDataToJSON(json) {
1352
+ return CompanyInvoiceResponseDataToJSONTyped(json, false);
1353
+ }
1354
+ function CompanyInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1355
+ if (value == null) {
1356
+ return value;
1357
+ }
1358
+ return {
1359
+ amount_due: value["amountDue"],
1360
+ created_at: value["createdAt"].toISOString(),
1361
+ currency: value["currency"],
1362
+ due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
1363
+ id: value["id"],
1364
+ status: InvoiceStatusToJSON(value["status"]),
1365
+ url: value["url"]
1366
+ };
1367
+ }
1368
+ function instanceOfCompanyInvoicesResponseData(value) {
1369
+ if (!("count" in value) || value["count"] === void 0) return false;
1370
+ if (!("invoices" in value) || value["invoices"] === void 0) return false;
1371
+ return true;
1372
+ }
1373
+ function CompanyInvoicesResponseDataFromJSON(json) {
1374
+ return CompanyInvoicesResponseDataFromJSONTyped(json, false);
1375
+ }
1376
+ function CompanyInvoicesResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1377
+ if (json == null) {
1378
+ return json;
1379
+ }
1380
+ return {
1381
+ count: json["count"],
1382
+ invoices: json["invoices"].map(
1383
+ CompanyInvoiceResponseDataFromJSON
1384
+ )
1385
+ };
1386
+ }
1387
+ function CompanyInvoicesResponseDataToJSON(json) {
1388
+ return CompanyInvoicesResponseDataToJSONTyped(json, false);
1389
+ }
1390
+ function CompanyInvoicesResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1391
+ if (value == null) {
1392
+ return value;
1393
+ }
1394
+ return {
1395
+ count: value["count"],
1396
+ invoices: value["invoices"].map(
1397
+ CompanyInvoiceResponseDataToJSON
1398
+ )
1399
+ };
1400
+ }
1401
+ function instanceOfCompanyUpcomingInvoiceResponseData(value) {
1402
+ if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
1403
+ if (!("currency" in value) || value["currency"] === void 0) return false;
1404
+ if (!("customerBalanceApplied" in value) || value["customerBalanceApplied"] === void 0)
1405
+ return false;
1406
+ if (!("customerBalanceRemaining" in value) || value["customerBalanceRemaining"] === void 0)
1407
+ return false;
1408
+ if (!("discounts" in value) || value["discounts"] === void 0) return false;
1409
+ if (!("subtotal" in value) || value["subtotal"] === void 0) return false;
1410
+ return true;
1411
+ }
1412
+ function CompanyUpcomingInvoiceResponseDataFromJSON(json) {
1413
+ return CompanyUpcomingInvoiceResponseDataFromJSONTyped(json, false);
1414
+ }
1415
+ function CompanyUpcomingInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1416
+ if (json == null) {
1417
+ return json;
1418
+ }
1419
+ return {
1420
+ amountDue: json["amount_due"],
1421
+ currency: json["currency"],
1422
+ customerBalanceApplied: json["customer_balance_applied"],
1423
+ customerBalanceRemaining: json["customer_balance_remaining"],
1424
+ discounts: json["discounts"].map(
1425
+ CompanyDiscountResponseDataFromJSON
1426
+ ),
1427
+ dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
1428
+ subtotal: json["subtotal"]
1429
+ };
1430
+ }
1431
+ function CompanyUpcomingInvoiceResponseDataToJSON(json) {
1432
+ return CompanyUpcomingInvoiceResponseDataToJSONTyped(json, false);
1433
+ }
1434
+ function CompanyUpcomingInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1435
+ if (value == null) {
1436
+ return value;
1437
+ }
1438
+ return {
1439
+ amount_due: value["amountDue"],
1440
+ currency: value["currency"],
1441
+ customer_balance_applied: value["customerBalanceApplied"],
1442
+ customer_balance_remaining: value["customerBalanceRemaining"],
1443
+ discounts: value["discounts"].map(
1444
+ CompanyDiscountResponseDataToJSON
1445
+ ),
1446
+ due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
1447
+ subtotal: value["subtotal"]
1448
+ };
1449
+ }
1450
+ function instanceOfGetCompanyInvoicesParams(value) {
1451
+ return true;
1452
+ }
1453
+ function GetCompanyInvoicesParamsFromJSON(json) {
1454
+ return GetCompanyInvoicesParamsFromJSONTyped(json, false);
1455
+ }
1456
+ function GetCompanyInvoicesParamsFromJSONTyped(json, ignoreDiscriminator) {
1457
+ if (json == null) {
1458
+ return json;
1459
+ }
1460
+ return {
1461
+ includePending: json["include_pending"] == null ? void 0 : json["include_pending"],
1462
+ limit: json["limit"] == null ? void 0 : json["limit"],
1463
+ offset: json["offset"] == null ? void 0 : json["offset"]
1464
+ };
1465
+ }
1466
+ function GetCompanyInvoicesParamsToJSON(json) {
1467
+ return GetCompanyInvoicesParamsToJSONTyped(json, false);
1468
+ }
1469
+ function GetCompanyInvoicesParamsToJSONTyped(value, ignoreDiscriminator = false) {
1470
+ if (value == null) {
1471
+ return value;
1472
+ }
1473
+ return {
1474
+ include_pending: value["includePending"],
1475
+ limit: value["limit"],
1476
+ offset: value["offset"]
1477
+ };
1478
+ }
1479
+ function instanceOfGetCompanyInvoicesResponse(value) {
1480
+ if (!("data" in value) || value["data"] === void 0) return false;
1481
+ if (!("params" in value) || value["params"] === void 0) return false;
1482
+ return true;
1483
+ }
1484
+ function GetCompanyInvoicesResponseFromJSON(json) {
1485
+ return GetCompanyInvoicesResponseFromJSONTyped(json, false);
1486
+ }
1487
+ function GetCompanyInvoicesResponseFromJSONTyped(json, ignoreDiscriminator) {
1488
+ if (json == null) {
1489
+ return json;
1490
+ }
1491
+ return {
1492
+ data: CompanyInvoicesResponseDataFromJSON(json["data"]),
1493
+ params: GetCompanyInvoicesParamsFromJSON(json["params"])
1494
+ };
1495
+ }
1496
+ function GetCompanyInvoicesResponseToJSON(json) {
1497
+ return GetCompanyInvoicesResponseToJSONTyped(json, false);
1498
+ }
1499
+ function GetCompanyInvoicesResponseToJSONTyped(value, ignoreDiscriminator = false) {
1500
+ if (value == null) {
1501
+ return value;
1502
+ }
1503
+ return {
1504
+ data: CompanyInvoicesResponseDataToJSON(value["data"]),
1505
+ params: GetCompanyInvoicesParamsToJSON(value["params"])
1506
+ };
1507
+ }
1508
+ function instanceOfGetCompanyUpcomingInvoiceResponse(value) {
1509
+ if (!("data" in value) || value["data"] === void 0) return false;
1510
+ if (!("params" in value) || value["params"] === void 0) return false;
1511
+ return true;
1512
+ }
1513
+ function GetCompanyUpcomingInvoiceResponseFromJSON(json) {
1514
+ return GetCompanyUpcomingInvoiceResponseFromJSONTyped(json, false);
1515
+ }
1516
+ function GetCompanyUpcomingInvoiceResponseFromJSONTyped(json, ignoreDiscriminator) {
1517
+ if (json == null) {
1518
+ return json;
1519
+ }
1520
+ return {
1521
+ data: CompanyUpcomingInvoiceResponseDataFromJSON(json["data"]),
1522
+ params: json["params"]
1523
+ };
1524
+ }
1525
+ function GetCompanyUpcomingInvoiceResponseToJSON(json) {
1526
+ return GetCompanyUpcomingInvoiceResponseToJSONTyped(json, false);
1527
+ }
1528
+ function GetCompanyUpcomingInvoiceResponseToJSONTyped(value, ignoreDiscriminator = false) {
1529
+ if (value == null) {
1530
+ return value;
1531
+ }
1532
+ return {
1533
+ data: CompanyUpcomingInvoiceResponseDataToJSON(value["data"]),
1534
+ params: value["params"]
1535
+ };
1536
+ }
864
1537
  var anonymousIdKey = "schematicId";
1538
+ var flagStateCachePrefix = "schematicCache";
1539
+ var flagStateCacheMaxContexts = 10;
1540
+ var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
1541
+ var emptyCreditBalances = Object.freeze({});
865
1542
  var Schematic = class {
866
- additionalHeaders = {};
1543
+ _additionalHeaders = {};
867
1544
  apiKey;
868
- apiUrl = "https://api.schematichq.com";
1545
+ _apiUrl = "https://api.schematichq.com";
869
1546
  conn = null;
870
1547
  context = {};
871
1548
  debugEnabled = false;
@@ -878,11 +1555,17 @@ var Schematic = class {
878
1555
  isPending = true;
879
1556
  isPendingListeners = /* @__PURE__ */ new Set();
880
1557
  planListeners = /* @__PURE__ */ new Set();
1558
+ creditBalanceListeners = /* @__PURE__ */ new Set();
881
1559
  storage;
1560
+ persistFlagState = true;
1561
+ flagStateCacheKey;
1562
+ flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
1563
+ cachedFlagState = null;
882
1564
  useWebSocket = false;
883
1565
  checks = {};
884
1566
  featureUsageEventMap = {};
885
1567
  planChecks = {};
1568
+ creditBalances = {};
886
1569
  webSocketUrl = "wss://api.schematichq.com";
887
1570
  webSocketConnectionTimeout = 1e4;
888
1571
  webSocketReconnect = true;
@@ -911,11 +1594,16 @@ var Schematic = class {
911
1594
  fallbackCheckCache = {};
912
1595
  constructor(apiKey, options) {
913
1596
  this.apiKey = apiKey;
1597
+ this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
914
1598
  this.eventQueue = [];
915
1599
  this.contextDependentEventQueue = [];
916
1600
  this.useWebSocket = options?.useWebSocket ?? false;
917
1601
  this.debugEnabled = options?.debug ?? false;
918
1602
  this.offlineEnabled = options?.offline ?? false;
1603
+ this.persistFlagState = options?.persistFlagState ?? true;
1604
+ if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
1605
+ this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
1606
+ }
919
1607
  if (typeof window !== "undefined" && typeof window.location !== "undefined") {
920
1608
  const params = new URLSearchParams(window.location.search);
921
1609
  const debugParam = params.get("schematic_debug");
@@ -934,7 +1622,7 @@ var Schematic = class {
934
1622
  if (this.offlineEnabled) {
935
1623
  this.setIsPending(false);
936
1624
  }
937
- this.additionalHeaders = {
1625
+ this._additionalHeaders = {
938
1626
  "X-Schematic-Client-Version": `schematic-js@${version}`,
939
1627
  ...options?.additionalHeaders ?? {}
940
1628
  };
@@ -948,8 +1636,9 @@ var Schematic = class {
948
1636
  } catch {
949
1637
  }
950
1638
  }
1639
+ this.hydrateFlagStateFromCache();
951
1640
  if (options?.apiUrl !== void 0) {
952
- this.apiUrl = options.apiUrl;
1641
+ this._apiUrl = options.apiUrl;
953
1642
  }
954
1643
  if (options?.eventUrl !== void 0) {
955
1644
  this.eventUrl = options.eventUrl;
@@ -1014,6 +1703,12 @@ var Schematic = class {
1014
1703
  this.debug("Initialized with debug mode enabled");
1015
1704
  }
1016
1705
  }
1706
+ get apiUrl() {
1707
+ return this._apiUrl;
1708
+ }
1709
+ get additionalHeaders() {
1710
+ return { ...this._additionalHeaders };
1711
+ }
1017
1712
  /**
1018
1713
  * Resolve fallback value according to priority order:
1019
1714
  * 1. Callsite fallback value (if provided)
@@ -1099,11 +1794,11 @@ var Schematic = class {
1099
1794
  return resolvedFallbackResult.value;
1100
1795
  }
1101
1796
  if (!this.useWebSocket) {
1102
- const requestUrl = `${this.apiUrl}/flags/${key}/check`;
1797
+ const requestUrl = `${this._apiUrl}/flags/${key}/check`;
1103
1798
  return fetch(requestUrl, {
1104
1799
  method: "POST",
1105
1800
  headers: {
1106
- ...this.additionalHeaders ?? {},
1801
+ ...this._additionalHeaders ?? {},
1107
1802
  "Content-Type": "application/json;charset=UTF-8",
1108
1803
  "X-Schematic-Api-Key": this.apiKey
1109
1804
  },
@@ -1241,6 +1936,29 @@ var Schematic = class {
1241
1936
  });
1242
1937
  this.notifyPlanListeners(plan);
1243
1938
  }
1939
+ if (message.credit_balances !== void 0 && message.credit_balances !== null) {
1940
+ const contextStr = contextString(context);
1941
+ const updates = CreditBalancesFromJSON(message.credit_balances);
1942
+ const previous = this.creditBalances[contextStr] ?? {};
1943
+ let changed = false;
1944
+ const merged = { ...previous };
1945
+ for (const [creditId, next] of Object.entries(updates)) {
1946
+ const current = previous[creditId];
1947
+ if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
1948
+ merged[creditId] = next;
1949
+ changed = true;
1950
+ }
1951
+ }
1952
+ if (changed) {
1953
+ this.creditBalances[contextStr] = merged;
1954
+ this.debug(
1955
+ `WebSocket credit balance update received. Notifying listeners`,
1956
+ { creditBalances: merged }
1957
+ );
1958
+ this.notifyCreditBalanceListeners(merged);
1959
+ }
1960
+ }
1961
+ this.persistContextToCache(contextString(context));
1244
1962
  this.flushContextDependentEventQueue();
1245
1963
  this.setIsPending(false);
1246
1964
  };
@@ -1283,12 +2001,12 @@ var Schematic = class {
1283
2001
  this.debug(`checkFlags offline result: returning empty object`);
1284
2002
  return {};
1285
2003
  }
1286
- const requestUrl = `${this.apiUrl}/flags/check`;
2004
+ const requestUrl = `${this._apiUrl}/flags/check`;
1287
2005
  const requestBody = JSON.stringify(context);
1288
2006
  return fetch(requestUrl, {
1289
2007
  method: "POST",
1290
2008
  headers: {
1291
- ...this.additionalHeaders ?? {},
2009
+ ...this._additionalHeaders ?? {},
1292
2010
  "Content-Type": "application/json;charset=UTF-8",
1293
2011
  "X-Schematic-Api-Key": this.apiKey
1294
2012
  },
@@ -1348,7 +2066,32 @@ var Schematic = class {
1348
2066
  return;
1349
2067
  }
1350
2068
  try {
1351
- this.setIsPending(true);
2069
+ const newContextStr = contextString(context);
2070
+ const cacheHit = this.hasCachedValuesForContext(newContextStr);
2071
+ if (cacheHit) {
2072
+ this.debug(
2073
+ `setContext: cache hit for context, pre-resolving from cached values`
2074
+ );
2075
+ this.context = context;
2076
+ this.flushContextDependentEventQueue();
2077
+ this.setIsPending(false);
2078
+ const cachedChecks = this.checks[newContextStr] ?? {};
2079
+ for (const [flagKey, check] of Object.entries(cachedChecks)) {
2080
+ if (check === void 0) continue;
2081
+ this.notifyFlagCheckListeners(flagKey, check);
2082
+ this.notifyFlagValueListeners(flagKey, check.value);
2083
+ }
2084
+ const cachedPlan = this.planChecks[newContextStr];
2085
+ if (cachedPlan !== void 0) {
2086
+ this.notifyPlanListeners(cachedPlan);
2087
+ }
2088
+ const cachedCreditBalances = this.creditBalances[newContextStr];
2089
+ if (cachedCreditBalances !== void 0) {
2090
+ this.notifyCreditBalanceListeners(cachedCreditBalances);
2091
+ }
2092
+ } else {
2093
+ this.setIsPending(true);
2094
+ }
1352
2095
  if (!this.conn) {
1353
2096
  if (this.isConnecting) {
1354
2097
  this.debug(
@@ -1359,7 +2102,7 @@ var Schematic = class {
1359
2102
  }
1360
2103
  if (this.conn !== null) {
1361
2104
  const socket2 = await this.conn;
1362
- await this.wsSendMessage(socket2, context);
2105
+ await this.wsSendMessage(socket2, context, cacheHit);
1363
2106
  return;
1364
2107
  }
1365
2108
  }
@@ -1375,7 +2118,7 @@ var Schematic = class {
1375
2118
  this.conn = this.wsConnect();
1376
2119
  const socket2 = await this.conn;
1377
2120
  this.isConnecting = false;
1378
- await this.wsSendMessage(socket2, context);
2121
+ await this.wsSendMessage(socket2, context, cacheHit);
1379
2122
  return;
1380
2123
  } catch (error) {
1381
2124
  this.isConnecting = false;
@@ -1383,7 +2126,7 @@ var Schematic = class {
1383
2126
  }
1384
2127
  }
1385
2128
  const socket = await this.conn;
1386
- await this.wsSendMessage(socket, context);
2129
+ await this.wsSendMessage(socket, context, cacheHit);
1387
2130
  } catch (error) {
1388
2131
  console.warn("Failed to establish WebSocket connection:", error);
1389
2132
  this.context = context;
@@ -1443,10 +2186,12 @@ var Schematic = class {
1443
2186
  `Optimistically updating feature usage for event: ${eventName}`,
1444
2187
  { quantity }
1445
2188
  );
2189
+ let dirty = false;
1446
2190
  Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
1447
2191
  if (check === void 0) return;
1448
2192
  const updatedCheck = { ...check };
1449
2193
  if (typeof updatedCheck.featureUsage === "number") {
2194
+ dirty = true;
1450
2195
  updatedCheck.featureUsage += quantity;
1451
2196
  if (typeof updatedCheck.featureAllocation === "number") {
1452
2197
  const wasExceeded = updatedCheck.featureUsageExceeded === true;
@@ -1476,6 +2221,9 @@ var Schematic = class {
1476
2221
  this.notifyFlagValueListeners(flagKey, updatedCheck.value);
1477
2222
  }
1478
2223
  });
2224
+ if (dirty) {
2225
+ this.persistContextToCache(contextString(this.context));
2226
+ }
1479
2227
  };
1480
2228
  /**
1481
2229
  * Event processing
@@ -1578,6 +2326,206 @@ var Schematic = class {
1578
2326
  this.storage.setItem(anonymousIdKey, generatedAnonymousId);
1579
2327
  return generatedAnonymousId;
1580
2328
  };
2329
+ hasCachedValuesForContext = (contextStr) => {
2330
+ const cachedChecks = this.checks[contextStr];
2331
+ if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
2332
+ return true;
2333
+ }
2334
+ if (this.planChecks[contextStr] !== void 0) {
2335
+ return true;
2336
+ }
2337
+ const cachedCreditBalances = this.creditBalances[contextStr];
2338
+ return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
2339
+ };
2340
+ readFlagStateCache = () => {
2341
+ if (!this.persistFlagState || this.storage === void 0) {
2342
+ return null;
2343
+ }
2344
+ let raw;
2345
+ try {
2346
+ raw = this.storage.getItem(this.flagStateCacheKey);
2347
+ } catch (error) {
2348
+ this.debug("Failed to read flag state cache:", error);
2349
+ return null;
2350
+ }
2351
+ if (raw === null || raw === void 0) {
2352
+ return null;
2353
+ }
2354
+ let parsed;
2355
+ try {
2356
+ parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
2357
+ } catch (error) {
2358
+ this.debug("Flag state cache is not valid JSON, ignoring:", error);
2359
+ return null;
2360
+ }
2361
+ if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
2362
+ this.debug(
2363
+ `Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
2364
+ {
2365
+ parsedType: typeof parsed,
2366
+ version: parsed?.version
2367
+ }
2368
+ );
2369
+ return null;
2370
+ }
2371
+ return parsed;
2372
+ };
2373
+ reviveCachedCheck = (raw) => {
2374
+ if (raw === null || typeof raw !== "object") return null;
2375
+ const obj = raw;
2376
+ if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
2377
+ return null;
2378
+ }
2379
+ const revived = { ...obj };
2380
+ if (typeof revived.featureUsageResetAt === "string") {
2381
+ const d = new Date(revived.featureUsageResetAt);
2382
+ revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
2383
+ }
2384
+ return revived;
2385
+ };
2386
+ reviveCachedPlan = (raw) => {
2387
+ if (raw === null || typeof raw !== "object") return null;
2388
+ const obj = raw;
2389
+ if (typeof obj.id !== "string" || typeof obj.name !== "string") {
2390
+ return null;
2391
+ }
2392
+ const revived = { ...obj };
2393
+ if (typeof revived.trialEndDate === "string") {
2394
+ const d = new Date(revived.trialEndDate);
2395
+ revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
2396
+ }
2397
+ return revived;
2398
+ };
2399
+ reviveCachedCreditBalances = (raw) => {
2400
+ if (raw === null || typeof raw !== "object") return null;
2401
+ const revived = {};
2402
+ for (const [creditId, value] of Object.entries(
2403
+ raw
2404
+ )) {
2405
+ if (value === null || typeof value !== "object") continue;
2406
+ const obj = value;
2407
+ if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
2408
+ continue;
2409
+ }
2410
+ revived[creditId] = {
2411
+ remaining: obj.remaining,
2412
+ reserved: obj.reserved,
2413
+ settled: obj.settled
2414
+ };
2415
+ }
2416
+ return Object.keys(revived).length > 0 ? revived : null;
2417
+ };
2418
+ hydrateFlagStateFromCache = () => {
2419
+ const parsed = this.readFlagStateCache();
2420
+ if (parsed === null) return;
2421
+ const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
2422
+ const fresh = {};
2423
+ let contextsLoaded = 0;
2424
+ let contextsExpired = 0;
2425
+ for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
2426
+ if (entry === null || typeof entry !== "object") continue;
2427
+ if (typeof entry.updatedAt !== "number") continue;
2428
+ if (entry.updatedAt < cutoff) {
2429
+ contextsExpired += 1;
2430
+ continue;
2431
+ }
2432
+ const revivedChecks = {};
2433
+ if (entry.checks !== null && typeof entry.checks === "object") {
2434
+ for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
2435
+ const revived = this.reviveCachedCheck(rawCheck);
2436
+ if (revived === null || revived.flag !== flagKey) continue;
2437
+ revivedChecks[flagKey] = revived;
2438
+ if (typeof revived.featureUsageEvent === "string") {
2439
+ this.updateFeatureUsageEventMap(revived);
2440
+ }
2441
+ }
2442
+ if (Object.keys(revivedChecks).length > 0) {
2443
+ this.checks[contextStr] = revivedChecks;
2444
+ }
2445
+ }
2446
+ let revivedPlan;
2447
+ if (entry.plan !== void 0 && entry.plan !== null) {
2448
+ const p = this.reviveCachedPlan(entry.plan);
2449
+ if (p !== null) {
2450
+ revivedPlan = p;
2451
+ this.planChecks[contextStr] = p;
2452
+ }
2453
+ }
2454
+ let revivedCreditBalances;
2455
+ if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
2456
+ const balances = this.reviveCachedCreditBalances(entry.creditBalances);
2457
+ if (balances !== null) {
2458
+ revivedCreditBalances = balances;
2459
+ this.creditBalances[contextStr] = balances;
2460
+ }
2461
+ }
2462
+ fresh[contextStr] = {
2463
+ checks: revivedChecks,
2464
+ plan: revivedPlan,
2465
+ creditBalances: revivedCreditBalances,
2466
+ updatedAt: entry.updatedAt
2467
+ };
2468
+ contextsLoaded += 1;
2469
+ }
2470
+ this.cachedFlagState = { version: cacheVersion, contexts: fresh };
2471
+ this.debug(
2472
+ `Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
2473
+ );
2474
+ };
2475
+ persistContextToCache = (contextStr) => {
2476
+ const checksForContext = this.checks[contextStr];
2477
+ const planForContext = this.planChecks[contextStr];
2478
+ const creditBalancesForContext = this.creditBalances[contextStr];
2479
+ if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
2480
+ return;
2481
+ }
2482
+ if (this.cachedFlagState === null) {
2483
+ this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
2484
+ version: cacheVersion,
2485
+ contexts: {}
2486
+ };
2487
+ }
2488
+ const cleanChecks = {};
2489
+ if (checksForContext !== void 0) {
2490
+ for (const [flagKey, check] of Object.entries(checksForContext)) {
2491
+ if (check !== void 0) cleanChecks[flagKey] = check;
2492
+ }
2493
+ }
2494
+ this.cachedFlagState.contexts[contextStr] = {
2495
+ checks: cleanChecks,
2496
+ plan: planForContext,
2497
+ creditBalances: creditBalancesForContext,
2498
+ updatedAt: Date.now()
2499
+ };
2500
+ const entries = Object.entries(this.cachedFlagState.contexts);
2501
+ if (entries.length > flagStateCacheMaxContexts) {
2502
+ entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
2503
+ const survivors = entries.slice(0, flagStateCacheMaxContexts);
2504
+ const survivorKeys = new Set(survivors.map(([k]) => k));
2505
+ for (const key of Object.keys(this.checks)) {
2506
+ if (!survivorKeys.has(key)) delete this.checks[key];
2507
+ }
2508
+ for (const key of Object.keys(this.planChecks)) {
2509
+ if (!survivorKeys.has(key)) delete this.planChecks[key];
2510
+ }
2511
+ for (const key of Object.keys(this.creditBalances)) {
2512
+ if (!survivorKeys.has(key)) delete this.creditBalances[key];
2513
+ }
2514
+ this.cachedFlagState = {
2515
+ version: cacheVersion,
2516
+ contexts: Object.fromEntries(survivors)
2517
+ };
2518
+ }
2519
+ if (!this.persistFlagState || this.storage === void 0) return;
2520
+ try {
2521
+ this.storage.setItem(
2522
+ this.flagStateCacheKey,
2523
+ JSON.stringify(this.cachedFlagState)
2524
+ );
2525
+ } catch (error) {
2526
+ this.debug("Failed to write flag state cache:", error);
2527
+ }
2528
+ };
1581
2529
  handleEvent = (eventType, eventBody) => {
1582
2530
  const event = {
1583
2531
  api_key: this.apiKey,
@@ -1605,7 +2553,7 @@ var Schematic = class {
1605
2553
  const response = await fetch(captureUrl, {
1606
2554
  method: "POST",
1607
2555
  headers: {
1608
- ...this.additionalHeaders ?? {},
2556
+ ...this._additionalHeaders ?? {},
1609
2557
  "Content-Type": "application/json;charset=UTF-8"
1610
2558
  },
1611
2559
  body: payload
@@ -1838,6 +2786,9 @@ var Schematic = class {
1838
2786
  if (this.conn !== null) {
1839
2787
  try {
1840
2788
  const socket = await this.conn;
2789
+ if (this.currentWebSocket === socket) {
2790
+ this.currentWebSocket = null;
2791
+ }
1841
2792
  if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
1842
2793
  socket.close();
1843
2794
  }
@@ -2003,6 +2954,7 @@ var Schematic = class {
2003
2954
  this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
2004
2955
  let timeoutId = null;
2005
2956
  let isResolved = false;
2957
+ let didOpen = false;
2006
2958
  timeoutId = setTimeout(() => {
2007
2959
  if (!isResolved) {
2008
2960
  isResolved = true;
@@ -2016,6 +2968,7 @@ var Schematic = class {
2016
2968
  webSocket.onopen = () => {
2017
2969
  if (isResolved) return;
2018
2970
  isResolved = true;
2971
+ didOpen = true;
2019
2972
  if (timeoutId !== null) {
2020
2973
  clearTimeout(timeoutId);
2021
2974
  }
@@ -2041,11 +2994,12 @@ var Schematic = class {
2041
2994
  }
2042
2995
  this.debug(`WebSocket connection ${connectionId} closed`);
2043
2996
  this.conn = null;
2997
+ const wasCurrent = this.currentWebSocket === webSocket;
2044
2998
  if (this.currentWebSocket === webSocket) {
2045
2999
  this.currentWebSocket = null;
2046
3000
  this.isConnecting = false;
2047
3001
  }
2048
- if (!isResolved && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
3002
+ if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
2049
3003
  this.attemptReconnect();
2050
3004
  }
2051
3005
  };
@@ -2095,7 +3049,7 @@ var Schematic = class {
2095
3049
  }
2096
3050
  });
2097
3051
  this.currentWebSocket = socket;
2098
- const clientVersion = this.additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
3052
+ const clientVersion = this._additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
2099
3053
  const messagePayload = {
2100
3054
  apiKey: this.apiKey,
2101
3055
  clientVersion,
@@ -2141,6 +3095,16 @@ var Schematic = class {
2141
3095
  const plan = this.planChecks[contextStr];
2142
3096
  return plan;
2143
3097
  };
3098
+ /** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
3099
+ getCreditBalances = () => {
3100
+ const contextStr = contextString(this.context);
3101
+ return this.creditBalances[contextStr] ?? emptyCreditBalances;
3102
+ };
3103
+ /** Get the company's lease-aware balance for a single credit type in the current context */
3104
+ getCreditBalance = (creditId) => {
3105
+ const contextStr = contextString(this.context);
3106
+ return this.creditBalances[contextStr]?.[creditId];
3107
+ };
2144
3108
  // flag checks state
2145
3109
  getFlagCheck = (flagKey) => {
2146
3110
  const contextStr = contextString(this.context);
@@ -2200,6 +3164,13 @@ var Schematic = class {
2200
3164
  this.planListeners.delete(listener);
2201
3165
  };
2202
3166
  };
3167
+ /** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
3168
+ addCreditBalanceListener = (listener) => {
3169
+ this.creditBalanceListeners.add(listener);
3170
+ return () => {
3171
+ this.creditBalanceListeners.delete(listener);
3172
+ };
3173
+ };
2203
3174
  notifyFlagCheckListeners = (flagKey, check) => {
2204
3175
  const listeners = this.flagCheckListeners?.[flagKey] ?? [];
2205
3176
  if (listeners.size > 0) {
@@ -2263,6 +3234,17 @@ var Schematic = class {
2263
3234
  });
2264
3235
  });
2265
3236
  };
3237
+ notifyCreditBalanceListeners = (value) => {
3238
+ const listeners = this.creditBalanceListeners ?? [];
3239
+ if (listeners.size > 0) {
3240
+ this.debug(`Notifying ${listeners.size} credit balance listeners`, {
3241
+ value
3242
+ });
3243
+ }
3244
+ listeners.forEach(
3245
+ (listener) => notifyCreditBalanceListener(listener, value)
3246
+ );
3247
+ };
2266
3248
  };
2267
3249
  var notifyPendingListener = (listener, value) => {
2268
3250
  if (listener.length > 0) {
@@ -2292,15 +3274,22 @@ var notifyPlanListener = (listener, value) => {
2292
3274
  listener();
2293
3275
  }
2294
3276
  };
3277
+ var notifyCreditBalanceListener = (listener, value) => {
3278
+ if (listener.length > 0) {
3279
+ listener(value);
3280
+ } else {
3281
+ listener();
3282
+ }
3283
+ };
2295
3284
 
2296
3285
  // src/context/schematic.ts
2297
3286
  var import_vue = require("vue");
2298
3287
 
2299
3288
  // src/version.ts
2300
- var version2 = "1.4.1";
3289
+ var version2 = "1.6.0";
2301
3290
 
2302
3291
  // src/context/schematic.ts
2303
- var SchematicSymbol = Symbol("schematic");
3292
+ var SchematicSymbol = /* @__PURE__ */ Symbol("schematic");
2304
3293
  var SchematicPlugin = {
2305
3294
  install(app, options) {
2306
3295
  let client;
@@ -2407,10 +3396,17 @@ var useSchematicEntitlement = (key, opts) => {
2407
3396
  featureUsageExceeded: (0, import_vue2.computed)(() => flagCheck.value.featureUsageExceeded),
2408
3397
  featureUsageEvent: (0, import_vue2.computed)(() => flagCheck.value.featureUsageEvent),
2409
3398
  featureUsagePeriod: (0, import_vue2.computed)(() => flagCheck.value.featureUsagePeriod),
3399
+ softLimit: (0, import_vue2.computed)(() => flagCheck.value.softLimit),
3400
+ warningTiers: (0, import_vue2.computed)(() => flagCheck.value.warningTiers),
2410
3401
  flagId: (0, import_vue2.computed)(() => flagCheck.value.flagId),
2411
3402
  ruleId: (0, import_vue2.computed)(() => flagCheck.value.ruleId),
2412
3403
  companyId: (0, import_vue2.computed)(() => flagCheck.value.companyId),
2413
- userId: (0, import_vue2.computed)(() => flagCheck.value.userId)
3404
+ userId: (0, import_vue2.computed)(() => flagCheck.value.userId),
3405
+ // Credit fields, populated for features metered by credit burndown
3406
+ creditId: (0, import_vue2.computed)(() => flagCheck.value.creditId),
3407
+ creditSettled: (0, import_vue2.computed)(() => flagCheck.value.creditSettled),
3408
+ creditRemaining: (0, import_vue2.computed)(() => flagCheck.value.creditRemaining),
3409
+ creditReserved: (0, import_vue2.computed)(() => flagCheck.value.creditReserved)
2414
3410
  };
2415
3411
  };
2416
3412
  var useSchematicPlan = (opts) => {
@@ -2430,6 +3426,44 @@ var useSchematicPlan = (opts) => {
2430
3426
  });
2431
3427
  return plan;
2432
3428
  };
3429
+ var useSchematicCreditBalance = (creditId, opts) => {
3430
+ const client = useSchematicClient(opts);
3431
+ const resolvedCreditId = (0, import_vue2.computed)(() => (0, import_vue2.toValue)(creditId));
3432
+ const readBalance = () => {
3433
+ const id = resolvedCreditId.value;
3434
+ return id === void 0 ? void 0 : client.getCreditBalance(id);
3435
+ };
3436
+ const creditBalance = (0, import_vue2.ref)(
3437
+ readBalance()
3438
+ );
3439
+ const isPending = (0, import_vue2.ref)(client.getIsPending());
3440
+ (0, import_vue2.watch)(resolvedCreditId, () => {
3441
+ creditBalance.value = readBalance();
3442
+ });
3443
+ let unsubscribeBalance = null;
3444
+ let unsubscribePending = null;
3445
+ (0, import_vue2.onMounted)(() => {
3446
+ creditBalance.value = readBalance();
3447
+ unsubscribeBalance = client.addCreditBalanceListener(() => {
3448
+ creditBalance.value = readBalance();
3449
+ });
3450
+ unsubscribePending = client.addIsPendingListener(() => {
3451
+ isPending.value = client.getIsPending();
3452
+ });
3453
+ });
3454
+ (0, import_vue2.onScopeDispose)(() => {
3455
+ unsubscribeBalance?.();
3456
+ unsubscribePending?.();
3457
+ });
3458
+ return {
3459
+ /** The spendable balance; 0 while loading or when the company holds no balance in this credit */
3460
+ balance: (0, import_vue2.computed)(() => creditBalance.value?.settled ?? 0),
3461
+ /** True while the balance is still loading and no value has arrived yet */
3462
+ isLoading: (0, import_vue2.computed)(
3463
+ () => creditBalance.value === void 0 && isPending.value
3464
+ )
3465
+ };
3466
+ };
2433
3467
  var useSchematicIsPending = (opts) => {
2434
3468
  const client = useSchematicClient(opts);
2435
3469
  const isPending = (0, import_vue2.ref)(client.getIsPending());