@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.
@@ -1,4 +1,4 @@
1
- // node_modules/@schematichq/schematic-js/dist/schematic.esm.js
1
+ // node_modules/.pnpm/@schematichq+schematic-js@1.8.0/node_modules/@schematichq/schematic-js/dist/schematic.esm.js
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -6,7 +6,15 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __commonJS = (cb, mod) => function __require() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ try {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ } catch (e) {
12
+ throw mod = 0, e;
13
+ }
14
+ };
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
10
18
  };
11
19
  var __copyProps = (to, from, except, desc) => {
12
20
  if (from && typeof from === "object" || typeof from === "function") {
@@ -25,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
33
  mod
26
34
  ));
27
35
  var require_browser_polyfill = __commonJS({
28
- "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
36
+ "node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
29
37
  (function(self2) {
30
38
  var irrelevant = (function(exports2) {
31
39
  var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
@@ -565,19 +573,16 @@ for (let i = 0; i < 256; ++i) {
565
573
  function unsafeStringify(arr, offset = 0) {
566
574
  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();
567
575
  }
568
- var getRandomValues;
569
576
  var rnds8 = new Uint8Array(16);
570
577
  function rng() {
571
- if (!getRandomValues) {
572
- if (typeof crypto === "undefined" || !crypto.getRandomValues) {
573
- throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
574
- }
575
- getRandomValues = crypto.getRandomValues.bind(crypto);
578
+ return crypto.getRandomValues(rnds8);
579
+ }
580
+ function v4(options, buf, offset) {
581
+ if (!buf && !options && crypto.randomUUID) {
582
+ return crypto.randomUUID();
576
583
  }
577
- return getRandomValues(rnds8);
584
+ return _v4(options, buf, offset);
578
585
  }
579
- var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
580
- var native_default = { randomUUID };
581
586
  function _v4(options, buf, offset) {
582
587
  options = options || {};
583
588
  const rnds = options.random ?? options.rng?.() ?? rng();
@@ -598,12 +603,6 @@ function _v4(options, buf, offset) {
598
603
  }
599
604
  return unsafeStringify(rnds);
600
605
  }
601
- function v4(options, buf, offset) {
602
- if (native_default.randomUUID && !buf && !options) {
603
- return native_default.randomUUID();
604
- }
605
- return _v4(options, buf, offset);
606
- }
607
606
  var v4_default = v4;
608
607
  var import_polyfill = __toESM(require_browser_polyfill());
609
608
  function EntitlementValueTypeFromJSON(json) {
@@ -612,6 +611,30 @@ function EntitlementValueTypeFromJSON(json) {
612
611
  function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
613
612
  return json;
614
613
  }
614
+ function MetricPeriodMonthResetFromJSON(json) {
615
+ return MetricPeriodMonthResetFromJSONTyped(json, false);
616
+ }
617
+ function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
618
+ return json;
619
+ }
620
+ function WarningTierFromJSON(json) {
621
+ return WarningTierFromJSONTyped(json, false);
622
+ }
623
+ function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
624
+ if (json == null) {
625
+ return json;
626
+ }
627
+ return {
628
+ key: json["key"],
629
+ value: json["value"]
630
+ };
631
+ }
632
+ function MetricPeriodFromJSON(json) {
633
+ return MetricPeriodFromJSONTyped(json, false);
634
+ }
635
+ function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
636
+ return json;
637
+ }
615
638
  function FeatureEntitlementFromJSON(json) {
616
639
  return FeatureEntitlementFromJSONTyped(json, false);
617
640
  }
@@ -621,21 +644,32 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
621
644
  }
622
645
  return {
623
646
  allocation: json["allocation"] == null ? void 0 : json["allocation"],
647
+ consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
624
648
  creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
625
649
  creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
650
+ creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
651
+ creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
626
652
  creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
627
653
  creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
628
654
  eventName: json["event_name"] == null ? void 0 : json["event_name"],
655
+ eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
629
656
  featureId: json["feature_id"],
630
657
  featureKey: json["feature_key"],
631
- metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
658
+ metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
632
659
  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"],
660
+ monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
634
661
  softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
635
662
  usage: json["usage"] == null ? void 0 : json["usage"],
636
- valueType: EntitlementValueTypeFromJSON(json["value_type"])
663
+ valueType: EntitlementValueTypeFromJSON(json["value_type"]),
664
+ warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
637
665
  };
638
666
  }
667
+ function RuleTypeFromJSON(json) {
668
+ return RuleTypeFromJSONTyped(json, false);
669
+ }
670
+ function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
671
+ return json;
672
+ }
639
673
  function CheckFlagResponseDataFromJSON(json) {
640
674
  return CheckFlagResponseDataFromJSONTyped(json, false);
641
675
  }
@@ -650,13 +684,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
650
684
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
651
685
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
652
686
  featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
653
- featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
687
+ featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
654
688
  featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
655
689
  flag: json["flag"],
656
690
  flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
657
691
  reason: json["reason"],
658
692
  ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
659
- ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
693
+ ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
660
694
  userId: json["user_id"] == null ? void 0 : json["user_id"],
661
695
  value: json["value"]
662
696
  };
@@ -673,6 +707,268 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
673
707
  params: json["params"]
674
708
  };
675
709
  }
710
+ var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
711
+ var Configuration = class {
712
+ constructor(configuration = {}) {
713
+ this.configuration = configuration;
714
+ }
715
+ configuration;
716
+ set config(configuration) {
717
+ this.configuration = configuration;
718
+ }
719
+ get basePath() {
720
+ return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
721
+ }
722
+ get fetchApi() {
723
+ return this.configuration.fetchApi;
724
+ }
725
+ get middleware() {
726
+ return this.configuration.middleware || [];
727
+ }
728
+ get queryParamsStringify() {
729
+ return this.configuration.queryParamsStringify || querystring;
730
+ }
731
+ get username() {
732
+ return this.configuration.username;
733
+ }
734
+ get password() {
735
+ return this.configuration.password;
736
+ }
737
+ get apiKey() {
738
+ const apiKey = this.configuration.apiKey;
739
+ if (apiKey) {
740
+ return typeof apiKey === "function" ? apiKey : () => apiKey;
741
+ }
742
+ return void 0;
743
+ }
744
+ get accessToken() {
745
+ const accessToken = this.configuration.accessToken;
746
+ if (accessToken) {
747
+ return typeof accessToken === "function" ? accessToken : async () => accessToken;
748
+ }
749
+ return void 0;
750
+ }
751
+ get headers() {
752
+ return this.configuration.headers;
753
+ }
754
+ get credentials() {
755
+ return this.configuration.credentials;
756
+ }
757
+ };
758
+ var DefaultConfig = new Configuration();
759
+ var BaseAPI = class _BaseAPI {
760
+ constructor(configuration = DefaultConfig) {
761
+ this.configuration = configuration;
762
+ this.middleware = configuration.middleware;
763
+ }
764
+ configuration;
765
+ static jsonRegex = new RegExp(
766
+ "^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
767
+ "i"
768
+ );
769
+ middleware;
770
+ withMiddleware(...middlewares) {
771
+ const next = this.clone();
772
+ next.middleware = next.middleware.concat(...middlewares);
773
+ return next;
774
+ }
775
+ withPreMiddleware(...preMiddlewares) {
776
+ const middlewares = preMiddlewares.map((pre) => ({ pre }));
777
+ return this.withMiddleware(...middlewares);
778
+ }
779
+ withPostMiddleware(...postMiddlewares) {
780
+ const middlewares = postMiddlewares.map((post) => ({ post }));
781
+ return this.withMiddleware(...middlewares);
782
+ }
783
+ /**
784
+ * Check if the given MIME is a JSON MIME.
785
+ * JSON MIME examples:
786
+ * application/json
787
+ * application/json; charset=UTF8
788
+ * APPLICATION/JSON
789
+ * application/vnd.company+json
790
+ * @param mime - MIME (Multipurpose Internet Mail Extensions)
791
+ * @return True if the given MIME is JSON, false otherwise.
792
+ */
793
+ isJsonMime(mime) {
794
+ if (!mime) {
795
+ return false;
796
+ }
797
+ return _BaseAPI.jsonRegex.test(mime);
798
+ }
799
+ async request(context, initOverrides) {
800
+ const { url, init } = await this.createFetchParams(context, initOverrides);
801
+ const response = await this.fetchApi(url, init);
802
+ if (response && response.status >= 200 && response.status < 300) {
803
+ return response;
804
+ }
805
+ throw new ResponseError(response, "Response returned an error code");
806
+ }
807
+ async createFetchParams(context, initOverrides) {
808
+ let url = this.configuration.basePath + context.path;
809
+ if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
810
+ url += "?" + this.configuration.queryParamsStringify(context.query);
811
+ }
812
+ const headers = Object.assign(
813
+ {},
814
+ this.configuration.headers,
815
+ context.headers
816
+ );
817
+ Object.keys(headers).forEach(
818
+ (key) => headers[key] === void 0 ? delete headers[key] : {}
819
+ );
820
+ const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
821
+ const initParams = {
822
+ method: context.method,
823
+ headers,
824
+ body: context.body,
825
+ credentials: this.configuration.credentials
826
+ };
827
+ const overriddenInit = {
828
+ ...initParams,
829
+ ...await initOverrideFn({
830
+ init: initParams,
831
+ context
832
+ })
833
+ };
834
+ let body;
835
+ if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
836
+ body = overriddenInit.body;
837
+ } else if (this.isJsonMime(headers["Content-Type"])) {
838
+ body = JSON.stringify(overriddenInit.body);
839
+ } else {
840
+ body = overriddenInit.body;
841
+ }
842
+ const init = {
843
+ ...overriddenInit,
844
+ body
845
+ };
846
+ return { url, init };
847
+ }
848
+ fetchApi = async (url, init) => {
849
+ let fetchParams = { url, init };
850
+ for (const middleware of this.middleware) {
851
+ if (middleware.pre) {
852
+ fetchParams = await middleware.pre({
853
+ fetch: this.fetchApi,
854
+ ...fetchParams
855
+ }) || fetchParams;
856
+ }
857
+ }
858
+ let response = void 0;
859
+ try {
860
+ response = await (this.configuration.fetchApi || fetch)(
861
+ fetchParams.url,
862
+ fetchParams.init
863
+ );
864
+ } catch (e) {
865
+ for (const middleware of this.middleware) {
866
+ if (middleware.onError) {
867
+ response = await middleware.onError({
868
+ fetch: this.fetchApi,
869
+ url: fetchParams.url,
870
+ init: fetchParams.init,
871
+ error: e,
872
+ response: response ? response.clone() : void 0
873
+ }) || response;
874
+ }
875
+ }
876
+ if (response === void 0) {
877
+ if (e instanceof Error) {
878
+ throw new FetchError(
879
+ e,
880
+ "The request failed and the interceptors did not return an alternative response"
881
+ );
882
+ } else {
883
+ throw e;
884
+ }
885
+ }
886
+ }
887
+ for (const middleware of this.middleware) {
888
+ if (middleware.post) {
889
+ response = await middleware.post({
890
+ fetch: this.fetchApi,
891
+ url: fetchParams.url,
892
+ init: fetchParams.init,
893
+ response: response.clone()
894
+ }) || response;
895
+ }
896
+ }
897
+ return response;
898
+ };
899
+ /**
900
+ * Create a shallow clone of `this` by constructing a new instance
901
+ * and then shallow cloning data members.
902
+ */
903
+ clone() {
904
+ const constructor = this.constructor;
905
+ const next = new constructor(this.configuration);
906
+ next.middleware = this.middleware.slice();
907
+ return next;
908
+ }
909
+ };
910
+ function isBlob(value) {
911
+ return typeof Blob !== "undefined" && value instanceof Blob;
912
+ }
913
+ function isFormData(value) {
914
+ return typeof FormData !== "undefined" && value instanceof FormData;
915
+ }
916
+ var ResponseError = class extends Error {
917
+ constructor(response, msg) {
918
+ super(msg);
919
+ this.response = response;
920
+ }
921
+ response;
922
+ name = "ResponseError";
923
+ };
924
+ var FetchError = class extends Error {
925
+ constructor(cause, msg) {
926
+ super(msg);
927
+ this.cause = cause;
928
+ }
929
+ cause;
930
+ name = "FetchError";
931
+ };
932
+ function querystring(params, prefix = "") {
933
+ return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
934
+ }
935
+ function querystringSingleKey(key, value, keyPrefix = "") {
936
+ const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
937
+ if (value instanceof Array) {
938
+ const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
939
+ return `${encodeURIComponent(fullKey)}=${multiValue}`;
940
+ }
941
+ if (value instanceof Set) {
942
+ const valueAsArray = Array.from(value);
943
+ return querystringSingleKey(key, valueAsArray, keyPrefix);
944
+ }
945
+ if (value instanceof Date) {
946
+ return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
947
+ }
948
+ if (value instanceof Object) {
949
+ return querystring(value, fullKey);
950
+ }
951
+ return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
952
+ }
953
+ function mapValues(data, fn) {
954
+ return Object.keys(data).reduce(
955
+ (acc, key) => ({ ...acc, [key]: fn(data[key]) }),
956
+ {}
957
+ );
958
+ }
959
+ function CompanyCreditBalanceFromJSON(json) {
960
+ return CompanyCreditBalanceFromJSONTyped(json, false);
961
+ }
962
+ function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
963
+ if (json == null) {
964
+ return json;
965
+ }
966
+ return {
967
+ remaining: json["remaining"],
968
+ reserved: json["reserved"],
969
+ settled: json["settled"]
970
+ };
971
+ }
676
972
  function TrialStatusFromJSON(json) {
677
973
  return TrialStatusFromJSONTyped(json, false);
678
974
  }
@@ -701,6 +997,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
701
997
  return json;
702
998
  }
703
999
  return {
1000
+ creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
704
1001
  flags: json["flags"].map(CheckFlagResponseDataFromJSON),
705
1002
  plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
706
1003
  };
@@ -729,6 +1026,7 @@ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
729
1026
  error: value["error"],
730
1027
  flag_id: value["flagId"],
731
1028
  flag_key: value["flagKey"],
1029
+ preflight: value["preflight"],
732
1030
  reason: value["reason"],
733
1031
  req_company: value["reqCompany"],
734
1032
  req_user: value["reqUser"],
@@ -783,7 +1081,10 @@ var CheckFlagReturnFromJSON = (json) => {
783
1081
  return {
784
1082
  featureUsageExceeded,
785
1083
  companyId: companyId == null ? void 0 : companyId,
1084
+ creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
786
1085
  creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
1086
+ creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
1087
+ creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
787
1088
  error: error == null ? void 0 : error,
788
1089
  featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
789
1090
  featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
@@ -797,7 +1098,8 @@ var CheckFlagReturnFromJSON = (json) => {
797
1098
  ruleType: ruleType == null ? void 0 : ruleType,
798
1099
  softLimit: entitlement?.softLimit == null ? void 0 : entitlement.softLimit,
799
1100
  userId: userId == null ? void 0 : userId,
800
- value
1101
+ value,
1102
+ warningTiers: entitlement?.warningTiers == null ? void 0 : entitlement.warningTiers
801
1103
  };
802
1104
  };
803
1105
  var CheckPlanReturnFromJSON = (json) => {
@@ -809,6 +1111,22 @@ var CheckPlanReturnFromJSON = (json) => {
809
1111
  trialStatus: trialStatus == null ? void 0 : trialStatus
810
1112
  };
811
1113
  };
1114
+ var CreditBalancesFromJSON = (json) => {
1115
+ if (json == null || typeof json !== "object") {
1116
+ return {};
1117
+ }
1118
+ const balances = {};
1119
+ for (const [creditId, raw] of Object.entries(json)) {
1120
+ if (raw == null || typeof raw !== "object") continue;
1121
+ const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
1122
+ if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
1123
+ continue;
1124
+ }
1125
+ balances[creditId] = { remaining, reserved, settled };
1126
+ }
1127
+ return balances;
1128
+ };
1129
+ var cacheVersion = "7b920cf4";
812
1130
  function contextString(context) {
813
1131
  const sortedContext = Object.keys(context).reduce((acc, key) => {
814
1132
  const sortedKeys = Object.keys(
@@ -823,12 +1141,370 @@ function contextString(context) {
823
1141
  }, {});
824
1142
  return JSON.stringify(sortedContext);
825
1143
  }
826
- var version = "1.4.0";
1144
+ var version = "1.8.0";
1145
+ var models_exports = {};
1146
+ __export(models_exports, {
1147
+ ApiErrorFromJSON: () => ApiErrorFromJSON,
1148
+ ApiErrorFromJSONTyped: () => ApiErrorFromJSONTyped,
1149
+ ApiErrorToJSON: () => ApiErrorToJSON,
1150
+ ApiErrorToJSONTyped: () => ApiErrorToJSONTyped,
1151
+ CompanyDiscountResponseDataFromJSON: () => CompanyDiscountResponseDataFromJSON,
1152
+ CompanyDiscountResponseDataFromJSONTyped: () => CompanyDiscountResponseDataFromJSONTyped,
1153
+ CompanyDiscountResponseDataToJSON: () => CompanyDiscountResponseDataToJSON,
1154
+ CompanyDiscountResponseDataToJSONTyped: () => CompanyDiscountResponseDataToJSONTyped,
1155
+ CompanyInvoiceResponseDataFromJSON: () => CompanyInvoiceResponseDataFromJSON,
1156
+ CompanyInvoiceResponseDataFromJSONTyped: () => CompanyInvoiceResponseDataFromJSONTyped,
1157
+ CompanyInvoiceResponseDataToJSON: () => CompanyInvoiceResponseDataToJSON,
1158
+ CompanyInvoiceResponseDataToJSONTyped: () => CompanyInvoiceResponseDataToJSONTyped,
1159
+ CompanyInvoicesResponseDataFromJSON: () => CompanyInvoicesResponseDataFromJSON,
1160
+ CompanyInvoicesResponseDataFromJSONTyped: () => CompanyInvoicesResponseDataFromJSONTyped,
1161
+ CompanyInvoicesResponseDataToJSON: () => CompanyInvoicesResponseDataToJSON,
1162
+ CompanyInvoicesResponseDataToJSONTyped: () => CompanyInvoicesResponseDataToJSONTyped,
1163
+ CompanyUpcomingInvoiceResponseDataFromJSON: () => CompanyUpcomingInvoiceResponseDataFromJSON,
1164
+ CompanyUpcomingInvoiceResponseDataFromJSONTyped: () => CompanyUpcomingInvoiceResponseDataFromJSONTyped,
1165
+ CompanyUpcomingInvoiceResponseDataToJSON: () => CompanyUpcomingInvoiceResponseDataToJSON,
1166
+ CompanyUpcomingInvoiceResponseDataToJSONTyped: () => CompanyUpcomingInvoiceResponseDataToJSONTyped,
1167
+ GetCompanyInvoicesParamsFromJSON: () => GetCompanyInvoicesParamsFromJSON,
1168
+ GetCompanyInvoicesParamsFromJSONTyped: () => GetCompanyInvoicesParamsFromJSONTyped,
1169
+ GetCompanyInvoicesParamsToJSON: () => GetCompanyInvoicesParamsToJSON,
1170
+ GetCompanyInvoicesParamsToJSONTyped: () => GetCompanyInvoicesParamsToJSONTyped,
1171
+ GetCompanyInvoicesResponseFromJSON: () => GetCompanyInvoicesResponseFromJSON,
1172
+ GetCompanyInvoicesResponseFromJSONTyped: () => GetCompanyInvoicesResponseFromJSONTyped,
1173
+ GetCompanyInvoicesResponseToJSON: () => GetCompanyInvoicesResponseToJSON,
1174
+ GetCompanyInvoicesResponseToJSONTyped: () => GetCompanyInvoicesResponseToJSONTyped,
1175
+ GetCompanyUpcomingInvoiceResponseFromJSON: () => GetCompanyUpcomingInvoiceResponseFromJSON,
1176
+ GetCompanyUpcomingInvoiceResponseFromJSONTyped: () => GetCompanyUpcomingInvoiceResponseFromJSONTyped,
1177
+ GetCompanyUpcomingInvoiceResponseToJSON: () => GetCompanyUpcomingInvoiceResponseToJSON,
1178
+ GetCompanyUpcomingInvoiceResponseToJSONTyped: () => GetCompanyUpcomingInvoiceResponseToJSONTyped,
1179
+ InvoiceStatus: () => InvoiceStatus,
1180
+ InvoiceStatusFromJSON: () => InvoiceStatusFromJSON,
1181
+ InvoiceStatusFromJSONTyped: () => InvoiceStatusFromJSONTyped,
1182
+ InvoiceStatusToJSON: () => InvoiceStatusToJSON,
1183
+ InvoiceStatusToJSONTyped: () => InvoiceStatusToJSONTyped,
1184
+ instanceOfApiError: () => instanceOfApiError,
1185
+ instanceOfCompanyDiscountResponseData: () => instanceOfCompanyDiscountResponseData,
1186
+ instanceOfCompanyInvoiceResponseData: () => instanceOfCompanyInvoiceResponseData,
1187
+ instanceOfCompanyInvoicesResponseData: () => instanceOfCompanyInvoicesResponseData,
1188
+ instanceOfCompanyUpcomingInvoiceResponseData: () => instanceOfCompanyUpcomingInvoiceResponseData,
1189
+ instanceOfGetCompanyInvoicesParams: () => instanceOfGetCompanyInvoicesParams,
1190
+ instanceOfGetCompanyInvoicesResponse: () => instanceOfGetCompanyInvoicesResponse,
1191
+ instanceOfGetCompanyUpcomingInvoiceResponse: () => instanceOfGetCompanyUpcomingInvoiceResponse,
1192
+ instanceOfInvoiceStatus: () => instanceOfInvoiceStatus
1193
+ });
1194
+ function instanceOfApiError(value) {
1195
+ if (!("error" in value) || value["error"] === void 0) return false;
1196
+ return true;
1197
+ }
1198
+ function ApiErrorFromJSON(json) {
1199
+ return ApiErrorFromJSONTyped(json, false);
1200
+ }
1201
+ function ApiErrorFromJSONTyped(json, ignoreDiscriminator) {
1202
+ if (json == null) {
1203
+ return json;
1204
+ }
1205
+ return {
1206
+ error: json["error"]
1207
+ };
1208
+ }
1209
+ function ApiErrorToJSON(json) {
1210
+ return ApiErrorToJSONTyped(json, false);
1211
+ }
1212
+ function ApiErrorToJSONTyped(value, ignoreDiscriminator = false) {
1213
+ if (value == null) {
1214
+ return value;
1215
+ }
1216
+ return {
1217
+ error: value["error"]
1218
+ };
1219
+ }
1220
+ function instanceOfCompanyDiscountResponseData(value) {
1221
+ if (!("couponName" in value) || value["couponName"] === void 0)
1222
+ return false;
1223
+ if (!("duration" in value) || value["duration"] === void 0) return false;
1224
+ return true;
1225
+ }
1226
+ function CompanyDiscountResponseDataFromJSON(json) {
1227
+ return CompanyDiscountResponseDataFromJSONTyped(json, false);
1228
+ }
1229
+ function CompanyDiscountResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1230
+ if (json == null) {
1231
+ return json;
1232
+ }
1233
+ return {
1234
+ amountOff: json["amount_off"] == null ? void 0 : json["amount_off"],
1235
+ couponName: json["coupon_name"],
1236
+ currency: json["currency"] == null ? void 0 : json["currency"],
1237
+ customerFacingCode: json["customer_facing_code"] == null ? void 0 : json["customer_facing_code"],
1238
+ duration: json["duration"],
1239
+ durationInMonths: json["duration_in_months"] == null ? void 0 : json["duration_in_months"],
1240
+ percentOff: json["percent_off"] == null ? void 0 : json["percent_off"]
1241
+ };
1242
+ }
1243
+ function CompanyDiscountResponseDataToJSON(json) {
1244
+ return CompanyDiscountResponseDataToJSONTyped(json, false);
1245
+ }
1246
+ function CompanyDiscountResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1247
+ if (value == null) {
1248
+ return value;
1249
+ }
1250
+ return {
1251
+ amount_off: value["amountOff"],
1252
+ coupon_name: value["couponName"],
1253
+ currency: value["currency"],
1254
+ customer_facing_code: value["customerFacingCode"],
1255
+ duration: value["duration"],
1256
+ duration_in_months: value["durationInMonths"],
1257
+ percent_off: value["percentOff"]
1258
+ };
1259
+ }
1260
+ var InvoiceStatus = {
1261
+ Draft: "draft",
1262
+ Open: "open",
1263
+ Paid: "paid",
1264
+ Uncollectible: "uncollectible",
1265
+ Void: "void"
1266
+ };
1267
+ function instanceOfInvoiceStatus(value) {
1268
+ for (const key in InvoiceStatus) {
1269
+ if (Object.prototype.hasOwnProperty.call(InvoiceStatus, key)) {
1270
+ if (InvoiceStatus[key] === value) {
1271
+ return true;
1272
+ }
1273
+ }
1274
+ }
1275
+ return false;
1276
+ }
1277
+ function InvoiceStatusFromJSON(json) {
1278
+ return InvoiceStatusFromJSONTyped(json, false);
1279
+ }
1280
+ function InvoiceStatusFromJSONTyped(json, ignoreDiscriminator) {
1281
+ return json;
1282
+ }
1283
+ function InvoiceStatusToJSON(value) {
1284
+ return value;
1285
+ }
1286
+ function InvoiceStatusToJSONTyped(value, ignoreDiscriminator) {
1287
+ return value;
1288
+ }
1289
+ function instanceOfCompanyInvoiceResponseData(value) {
1290
+ if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
1291
+ if (!("createdAt" in value) || value["createdAt"] === void 0) return false;
1292
+ if (!("currency" in value) || value["currency"] === void 0) return false;
1293
+ if (!("id" in value) || value["id"] === void 0) return false;
1294
+ return true;
1295
+ }
1296
+ function CompanyInvoiceResponseDataFromJSON(json) {
1297
+ return CompanyInvoiceResponseDataFromJSONTyped(json, false);
1298
+ }
1299
+ function CompanyInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1300
+ if (json == null) {
1301
+ return json;
1302
+ }
1303
+ return {
1304
+ amountDue: json["amount_due"],
1305
+ createdAt: new Date(json["created_at"]),
1306
+ currency: json["currency"],
1307
+ dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
1308
+ id: json["id"],
1309
+ status: json["status"] == null ? void 0 : InvoiceStatusFromJSON(json["status"]),
1310
+ url: json["url"] == null ? void 0 : json["url"]
1311
+ };
1312
+ }
1313
+ function CompanyInvoiceResponseDataToJSON(json) {
1314
+ return CompanyInvoiceResponseDataToJSONTyped(json, false);
1315
+ }
1316
+ function CompanyInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1317
+ if (value == null) {
1318
+ return value;
1319
+ }
1320
+ return {
1321
+ amount_due: value["amountDue"],
1322
+ created_at: value["createdAt"].toISOString(),
1323
+ currency: value["currency"],
1324
+ due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
1325
+ id: value["id"],
1326
+ status: InvoiceStatusToJSON(value["status"]),
1327
+ url: value["url"]
1328
+ };
1329
+ }
1330
+ function instanceOfCompanyInvoicesResponseData(value) {
1331
+ if (!("count" in value) || value["count"] === void 0) return false;
1332
+ if (!("invoices" in value) || value["invoices"] === void 0) return false;
1333
+ return true;
1334
+ }
1335
+ function CompanyInvoicesResponseDataFromJSON(json) {
1336
+ return CompanyInvoicesResponseDataFromJSONTyped(json, false);
1337
+ }
1338
+ function CompanyInvoicesResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1339
+ if (json == null) {
1340
+ return json;
1341
+ }
1342
+ return {
1343
+ count: json["count"],
1344
+ invoices: json["invoices"].map(
1345
+ CompanyInvoiceResponseDataFromJSON
1346
+ )
1347
+ };
1348
+ }
1349
+ function CompanyInvoicesResponseDataToJSON(json) {
1350
+ return CompanyInvoicesResponseDataToJSONTyped(json, false);
1351
+ }
1352
+ function CompanyInvoicesResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1353
+ if (value == null) {
1354
+ return value;
1355
+ }
1356
+ return {
1357
+ count: value["count"],
1358
+ invoices: value["invoices"].map(
1359
+ CompanyInvoiceResponseDataToJSON
1360
+ )
1361
+ };
1362
+ }
1363
+ function instanceOfCompanyUpcomingInvoiceResponseData(value) {
1364
+ if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
1365
+ if (!("currency" in value) || value["currency"] === void 0) return false;
1366
+ if (!("customerBalanceApplied" in value) || value["customerBalanceApplied"] === void 0)
1367
+ return false;
1368
+ if (!("customerBalanceRemaining" in value) || value["customerBalanceRemaining"] === void 0)
1369
+ return false;
1370
+ if (!("discounts" in value) || value["discounts"] === void 0) return false;
1371
+ if (!("subtotal" in value) || value["subtotal"] === void 0) return false;
1372
+ return true;
1373
+ }
1374
+ function CompanyUpcomingInvoiceResponseDataFromJSON(json) {
1375
+ return CompanyUpcomingInvoiceResponseDataFromJSONTyped(json, false);
1376
+ }
1377
+ function CompanyUpcomingInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1378
+ if (json == null) {
1379
+ return json;
1380
+ }
1381
+ return {
1382
+ amountDue: json["amount_due"],
1383
+ currency: json["currency"],
1384
+ customerBalanceApplied: json["customer_balance_applied"],
1385
+ customerBalanceRemaining: json["customer_balance_remaining"],
1386
+ discounts: json["discounts"].map(
1387
+ CompanyDiscountResponseDataFromJSON
1388
+ ),
1389
+ dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
1390
+ subtotal: json["subtotal"]
1391
+ };
1392
+ }
1393
+ function CompanyUpcomingInvoiceResponseDataToJSON(json) {
1394
+ return CompanyUpcomingInvoiceResponseDataToJSONTyped(json, false);
1395
+ }
1396
+ function CompanyUpcomingInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1397
+ if (value == null) {
1398
+ return value;
1399
+ }
1400
+ return {
1401
+ amount_due: value["amountDue"],
1402
+ currency: value["currency"],
1403
+ customer_balance_applied: value["customerBalanceApplied"],
1404
+ customer_balance_remaining: value["customerBalanceRemaining"],
1405
+ discounts: value["discounts"].map(
1406
+ CompanyDiscountResponseDataToJSON
1407
+ ),
1408
+ due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
1409
+ subtotal: value["subtotal"]
1410
+ };
1411
+ }
1412
+ function instanceOfGetCompanyInvoicesParams(value) {
1413
+ return true;
1414
+ }
1415
+ function GetCompanyInvoicesParamsFromJSON(json) {
1416
+ return GetCompanyInvoicesParamsFromJSONTyped(json, false);
1417
+ }
1418
+ function GetCompanyInvoicesParamsFromJSONTyped(json, ignoreDiscriminator) {
1419
+ if (json == null) {
1420
+ return json;
1421
+ }
1422
+ return {
1423
+ includePending: json["include_pending"] == null ? void 0 : json["include_pending"],
1424
+ limit: json["limit"] == null ? void 0 : json["limit"],
1425
+ offset: json["offset"] == null ? void 0 : json["offset"]
1426
+ };
1427
+ }
1428
+ function GetCompanyInvoicesParamsToJSON(json) {
1429
+ return GetCompanyInvoicesParamsToJSONTyped(json, false);
1430
+ }
1431
+ function GetCompanyInvoicesParamsToJSONTyped(value, ignoreDiscriminator = false) {
1432
+ if (value == null) {
1433
+ return value;
1434
+ }
1435
+ return {
1436
+ include_pending: value["includePending"],
1437
+ limit: value["limit"],
1438
+ offset: value["offset"]
1439
+ };
1440
+ }
1441
+ function instanceOfGetCompanyInvoicesResponse(value) {
1442
+ if (!("data" in value) || value["data"] === void 0) return false;
1443
+ if (!("params" in value) || value["params"] === void 0) return false;
1444
+ return true;
1445
+ }
1446
+ function GetCompanyInvoicesResponseFromJSON(json) {
1447
+ return GetCompanyInvoicesResponseFromJSONTyped(json, false);
1448
+ }
1449
+ function GetCompanyInvoicesResponseFromJSONTyped(json, ignoreDiscriminator) {
1450
+ if (json == null) {
1451
+ return json;
1452
+ }
1453
+ return {
1454
+ data: CompanyInvoicesResponseDataFromJSON(json["data"]),
1455
+ params: GetCompanyInvoicesParamsFromJSON(json["params"])
1456
+ };
1457
+ }
1458
+ function GetCompanyInvoicesResponseToJSON(json) {
1459
+ return GetCompanyInvoicesResponseToJSONTyped(json, false);
1460
+ }
1461
+ function GetCompanyInvoicesResponseToJSONTyped(value, ignoreDiscriminator = false) {
1462
+ if (value == null) {
1463
+ return value;
1464
+ }
1465
+ return {
1466
+ data: CompanyInvoicesResponseDataToJSON(value["data"]),
1467
+ params: GetCompanyInvoicesParamsToJSON(value["params"])
1468
+ };
1469
+ }
1470
+ function instanceOfGetCompanyUpcomingInvoiceResponse(value) {
1471
+ if (!("data" in value) || value["data"] === void 0) return false;
1472
+ if (!("params" in value) || value["params"] === void 0) return false;
1473
+ return true;
1474
+ }
1475
+ function GetCompanyUpcomingInvoiceResponseFromJSON(json) {
1476
+ return GetCompanyUpcomingInvoiceResponseFromJSONTyped(json, false);
1477
+ }
1478
+ function GetCompanyUpcomingInvoiceResponseFromJSONTyped(json, ignoreDiscriminator) {
1479
+ if (json == null) {
1480
+ return json;
1481
+ }
1482
+ return {
1483
+ data: CompanyUpcomingInvoiceResponseDataFromJSON(json["data"]),
1484
+ params: json["params"]
1485
+ };
1486
+ }
1487
+ function GetCompanyUpcomingInvoiceResponseToJSON(json) {
1488
+ return GetCompanyUpcomingInvoiceResponseToJSONTyped(json, false);
1489
+ }
1490
+ function GetCompanyUpcomingInvoiceResponseToJSONTyped(value, ignoreDiscriminator = false) {
1491
+ if (value == null) {
1492
+ return value;
1493
+ }
1494
+ return {
1495
+ data: CompanyUpcomingInvoiceResponseDataToJSON(value["data"]),
1496
+ params: value["params"]
1497
+ };
1498
+ }
827
1499
  var anonymousIdKey = "schematicId";
1500
+ var flagStateCachePrefix = "schematicCache";
1501
+ var flagStateCacheMaxContexts = 10;
1502
+ var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
1503
+ var emptyCreditBalances = Object.freeze({});
828
1504
  var Schematic = class {
829
- additionalHeaders = {};
1505
+ _additionalHeaders = {};
830
1506
  apiKey;
831
- apiUrl = "https://api.schematichq.com";
1507
+ _apiUrl = "https://api.schematichq.com";
832
1508
  conn = null;
833
1509
  context = {};
834
1510
  debugEnabled = false;
@@ -841,11 +1517,17 @@ var Schematic = class {
841
1517
  isPending = true;
842
1518
  isPendingListeners = /* @__PURE__ */ new Set();
843
1519
  planListeners = /* @__PURE__ */ new Set();
1520
+ creditBalanceListeners = /* @__PURE__ */ new Set();
844
1521
  storage;
1522
+ persistFlagState = true;
1523
+ flagStateCacheKey;
1524
+ flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
1525
+ cachedFlagState = null;
845
1526
  useWebSocket = false;
846
1527
  checks = {};
847
1528
  featureUsageEventMap = {};
848
1529
  planChecks = {};
1530
+ creditBalances = {};
849
1531
  webSocketUrl = "wss://api.schematichq.com";
850
1532
  webSocketConnectionTimeout = 1e4;
851
1533
  webSocketReconnect = true;
@@ -874,11 +1556,16 @@ var Schematic = class {
874
1556
  fallbackCheckCache = {};
875
1557
  constructor(apiKey, options) {
876
1558
  this.apiKey = apiKey;
1559
+ this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
877
1560
  this.eventQueue = [];
878
1561
  this.contextDependentEventQueue = [];
879
1562
  this.useWebSocket = options?.useWebSocket ?? false;
880
1563
  this.debugEnabled = options?.debug ?? false;
881
1564
  this.offlineEnabled = options?.offline ?? false;
1565
+ this.persistFlagState = options?.persistFlagState ?? true;
1566
+ if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
1567
+ this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
1568
+ }
882
1569
  if (typeof window !== "undefined" && typeof window.location !== "undefined") {
883
1570
  const params = new URLSearchParams(window.location.search);
884
1571
  const debugParam = params.get("schematic_debug");
@@ -897,7 +1584,7 @@ var Schematic = class {
897
1584
  if (this.offlineEnabled) {
898
1585
  this.setIsPending(false);
899
1586
  }
900
- this.additionalHeaders = {
1587
+ this._additionalHeaders = {
901
1588
  "X-Schematic-Client-Version": `schematic-js@${version}`,
902
1589
  ...options?.additionalHeaders ?? {}
903
1590
  };
@@ -911,8 +1598,9 @@ var Schematic = class {
911
1598
  } catch {
912
1599
  }
913
1600
  }
1601
+ this.hydrateFlagStateFromCache();
914
1602
  if (options?.apiUrl !== void 0) {
915
- this.apiUrl = options.apiUrl;
1603
+ this._apiUrl = options.apiUrl;
916
1604
  }
917
1605
  if (options?.eventUrl !== void 0) {
918
1606
  this.eventUrl = options.eventUrl;
@@ -977,6 +1665,12 @@ var Schematic = class {
977
1665
  this.debug("Initialized with debug mode enabled");
978
1666
  }
979
1667
  }
1668
+ get apiUrl() {
1669
+ return this._apiUrl;
1670
+ }
1671
+ get additionalHeaders() {
1672
+ return { ...this._additionalHeaders };
1673
+ }
980
1674
  /**
981
1675
  * Resolve fallback value according to priority order:
982
1676
  * 1. Callsite fallback value (if provided)
@@ -1062,11 +1756,11 @@ var Schematic = class {
1062
1756
  return resolvedFallbackResult.value;
1063
1757
  }
1064
1758
  if (!this.useWebSocket) {
1065
- const requestUrl = `${this.apiUrl}/flags/${key}/check`;
1759
+ const requestUrl = `${this._apiUrl}/flags/${key}/check`;
1066
1760
  return fetch(requestUrl, {
1067
1761
  method: "POST",
1068
1762
  headers: {
1069
- ...this.additionalHeaders ?? {},
1763
+ ...this._additionalHeaders ?? {},
1070
1764
  "Content-Type": "application/json;charset=UTF-8",
1071
1765
  "X-Schematic-Api-Key": this.apiKey
1072
1766
  },
@@ -1204,6 +1898,29 @@ var Schematic = class {
1204
1898
  });
1205
1899
  this.notifyPlanListeners(plan);
1206
1900
  }
1901
+ if (message.credit_balances !== void 0 && message.credit_balances !== null) {
1902
+ const contextStr = contextString(context);
1903
+ const updates = CreditBalancesFromJSON(message.credit_balances);
1904
+ const previous = this.creditBalances[contextStr] ?? {};
1905
+ let changed = false;
1906
+ const merged = { ...previous };
1907
+ for (const [creditId, next] of Object.entries(updates)) {
1908
+ const current = previous[creditId];
1909
+ if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
1910
+ merged[creditId] = next;
1911
+ changed = true;
1912
+ }
1913
+ }
1914
+ if (changed) {
1915
+ this.creditBalances[contextStr] = merged;
1916
+ this.debug(
1917
+ `WebSocket credit balance update received. Notifying listeners`,
1918
+ { creditBalances: merged }
1919
+ );
1920
+ this.notifyCreditBalanceListeners(merged);
1921
+ }
1922
+ }
1923
+ this.persistContextToCache(contextString(context));
1207
1924
  this.flushContextDependentEventQueue();
1208
1925
  this.setIsPending(false);
1209
1926
  };
@@ -1246,12 +1963,12 @@ var Schematic = class {
1246
1963
  this.debug(`checkFlags offline result: returning empty object`);
1247
1964
  return {};
1248
1965
  }
1249
- const requestUrl = `${this.apiUrl}/flags/check`;
1966
+ const requestUrl = `${this._apiUrl}/flags/check`;
1250
1967
  const requestBody = JSON.stringify(context);
1251
1968
  return fetch(requestUrl, {
1252
1969
  method: "POST",
1253
1970
  headers: {
1254
- ...this.additionalHeaders ?? {},
1971
+ ...this._additionalHeaders ?? {},
1255
1972
  "Content-Type": "application/json;charset=UTF-8",
1256
1973
  "X-Schematic-Api-Key": this.apiKey
1257
1974
  },
@@ -1311,7 +2028,32 @@ var Schematic = class {
1311
2028
  return;
1312
2029
  }
1313
2030
  try {
1314
- this.setIsPending(true);
2031
+ const newContextStr = contextString(context);
2032
+ const cacheHit = this.hasCachedValuesForContext(newContextStr);
2033
+ if (cacheHit) {
2034
+ this.debug(
2035
+ `setContext: cache hit for context, pre-resolving from cached values`
2036
+ );
2037
+ this.context = context;
2038
+ this.flushContextDependentEventQueue();
2039
+ this.setIsPending(false);
2040
+ const cachedChecks = this.checks[newContextStr] ?? {};
2041
+ for (const [flagKey, check] of Object.entries(cachedChecks)) {
2042
+ if (check === void 0) continue;
2043
+ this.notifyFlagCheckListeners(flagKey, check);
2044
+ this.notifyFlagValueListeners(flagKey, check.value);
2045
+ }
2046
+ const cachedPlan = this.planChecks[newContextStr];
2047
+ if (cachedPlan !== void 0) {
2048
+ this.notifyPlanListeners(cachedPlan);
2049
+ }
2050
+ const cachedCreditBalances = this.creditBalances[newContextStr];
2051
+ if (cachedCreditBalances !== void 0) {
2052
+ this.notifyCreditBalanceListeners(cachedCreditBalances);
2053
+ }
2054
+ } else {
2055
+ this.setIsPending(true);
2056
+ }
1315
2057
  if (!this.conn) {
1316
2058
  if (this.isConnecting) {
1317
2059
  this.debug(
@@ -1322,7 +2064,7 @@ var Schematic = class {
1322
2064
  }
1323
2065
  if (this.conn !== null) {
1324
2066
  const socket2 = await this.conn;
1325
- await this.wsSendMessage(socket2, context);
2067
+ await this.wsSendMessage(socket2, context, cacheHit);
1326
2068
  return;
1327
2069
  }
1328
2070
  }
@@ -1338,7 +2080,7 @@ var Schematic = class {
1338
2080
  this.conn = this.wsConnect();
1339
2081
  const socket2 = await this.conn;
1340
2082
  this.isConnecting = false;
1341
- await this.wsSendMessage(socket2, context);
2083
+ await this.wsSendMessage(socket2, context, cacheHit);
1342
2084
  return;
1343
2085
  } catch (error) {
1344
2086
  this.isConnecting = false;
@@ -1346,7 +2088,7 @@ var Schematic = class {
1346
2088
  }
1347
2089
  }
1348
2090
  const socket = await this.conn;
1349
- await this.wsSendMessage(socket, context);
2091
+ await this.wsSendMessage(socket, context, cacheHit);
1350
2092
  } catch (error) {
1351
2093
  console.warn("Failed to establish WebSocket connection:", error);
1352
2094
  this.context = context;
@@ -1406,10 +2148,12 @@ var Schematic = class {
1406
2148
  `Optimistically updating feature usage for event: ${eventName}`,
1407
2149
  { quantity }
1408
2150
  );
2151
+ let dirty = false;
1409
2152
  Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
1410
2153
  if (check === void 0) return;
1411
2154
  const updatedCheck = { ...check };
1412
2155
  if (typeof updatedCheck.featureUsage === "number") {
2156
+ dirty = true;
1413
2157
  updatedCheck.featureUsage += quantity;
1414
2158
  if (typeof updatedCheck.featureAllocation === "number") {
1415
2159
  const wasExceeded = updatedCheck.featureUsageExceeded === true;
@@ -1439,6 +2183,9 @@ var Schematic = class {
1439
2183
  this.notifyFlagValueListeners(flagKey, updatedCheck.value);
1440
2184
  }
1441
2185
  });
2186
+ if (dirty) {
2187
+ this.persistContextToCache(contextString(this.context));
2188
+ }
1442
2189
  };
1443
2190
  /**
1444
2191
  * Event processing
@@ -1541,6 +2288,206 @@ var Schematic = class {
1541
2288
  this.storage.setItem(anonymousIdKey, generatedAnonymousId);
1542
2289
  return generatedAnonymousId;
1543
2290
  };
2291
+ hasCachedValuesForContext = (contextStr) => {
2292
+ const cachedChecks = this.checks[contextStr];
2293
+ if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
2294
+ return true;
2295
+ }
2296
+ if (this.planChecks[contextStr] !== void 0) {
2297
+ return true;
2298
+ }
2299
+ const cachedCreditBalances = this.creditBalances[contextStr];
2300
+ return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
2301
+ };
2302
+ readFlagStateCache = () => {
2303
+ if (!this.persistFlagState || this.storage === void 0) {
2304
+ return null;
2305
+ }
2306
+ let raw;
2307
+ try {
2308
+ raw = this.storage.getItem(this.flagStateCacheKey);
2309
+ } catch (error) {
2310
+ this.debug("Failed to read flag state cache:", error);
2311
+ return null;
2312
+ }
2313
+ if (raw === null || raw === void 0) {
2314
+ return null;
2315
+ }
2316
+ let parsed;
2317
+ try {
2318
+ parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
2319
+ } catch (error) {
2320
+ this.debug("Flag state cache is not valid JSON, ignoring:", error);
2321
+ return null;
2322
+ }
2323
+ if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
2324
+ this.debug(
2325
+ `Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
2326
+ {
2327
+ parsedType: typeof parsed,
2328
+ version: parsed?.version
2329
+ }
2330
+ );
2331
+ return null;
2332
+ }
2333
+ return parsed;
2334
+ };
2335
+ reviveCachedCheck = (raw) => {
2336
+ if (raw === null || typeof raw !== "object") return null;
2337
+ const obj = raw;
2338
+ if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
2339
+ return null;
2340
+ }
2341
+ const revived = { ...obj };
2342
+ if (typeof revived.featureUsageResetAt === "string") {
2343
+ const d = new Date(revived.featureUsageResetAt);
2344
+ revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
2345
+ }
2346
+ return revived;
2347
+ };
2348
+ reviveCachedPlan = (raw) => {
2349
+ if (raw === null || typeof raw !== "object") return null;
2350
+ const obj = raw;
2351
+ if (typeof obj.id !== "string" || typeof obj.name !== "string") {
2352
+ return null;
2353
+ }
2354
+ const revived = { ...obj };
2355
+ if (typeof revived.trialEndDate === "string") {
2356
+ const d = new Date(revived.trialEndDate);
2357
+ revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
2358
+ }
2359
+ return revived;
2360
+ };
2361
+ reviveCachedCreditBalances = (raw) => {
2362
+ if (raw === null || typeof raw !== "object") return null;
2363
+ const revived = {};
2364
+ for (const [creditId, value] of Object.entries(
2365
+ raw
2366
+ )) {
2367
+ if (value === null || typeof value !== "object") continue;
2368
+ const obj = value;
2369
+ if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
2370
+ continue;
2371
+ }
2372
+ revived[creditId] = {
2373
+ remaining: obj.remaining,
2374
+ reserved: obj.reserved,
2375
+ settled: obj.settled
2376
+ };
2377
+ }
2378
+ return Object.keys(revived).length > 0 ? revived : null;
2379
+ };
2380
+ hydrateFlagStateFromCache = () => {
2381
+ const parsed = this.readFlagStateCache();
2382
+ if (parsed === null) return;
2383
+ const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
2384
+ const fresh = {};
2385
+ let contextsLoaded = 0;
2386
+ let contextsExpired = 0;
2387
+ for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
2388
+ if (entry === null || typeof entry !== "object") continue;
2389
+ if (typeof entry.updatedAt !== "number") continue;
2390
+ if (entry.updatedAt < cutoff) {
2391
+ contextsExpired += 1;
2392
+ continue;
2393
+ }
2394
+ const revivedChecks = {};
2395
+ if (entry.checks !== null && typeof entry.checks === "object") {
2396
+ for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
2397
+ const revived = this.reviveCachedCheck(rawCheck);
2398
+ if (revived === null || revived.flag !== flagKey) continue;
2399
+ revivedChecks[flagKey] = revived;
2400
+ if (typeof revived.featureUsageEvent === "string") {
2401
+ this.updateFeatureUsageEventMap(revived);
2402
+ }
2403
+ }
2404
+ if (Object.keys(revivedChecks).length > 0) {
2405
+ this.checks[contextStr] = revivedChecks;
2406
+ }
2407
+ }
2408
+ let revivedPlan;
2409
+ if (entry.plan !== void 0 && entry.plan !== null) {
2410
+ const p = this.reviveCachedPlan(entry.plan);
2411
+ if (p !== null) {
2412
+ revivedPlan = p;
2413
+ this.planChecks[contextStr] = p;
2414
+ }
2415
+ }
2416
+ let revivedCreditBalances;
2417
+ if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
2418
+ const balances = this.reviveCachedCreditBalances(entry.creditBalances);
2419
+ if (balances !== null) {
2420
+ revivedCreditBalances = balances;
2421
+ this.creditBalances[contextStr] = balances;
2422
+ }
2423
+ }
2424
+ fresh[contextStr] = {
2425
+ checks: revivedChecks,
2426
+ plan: revivedPlan,
2427
+ creditBalances: revivedCreditBalances,
2428
+ updatedAt: entry.updatedAt
2429
+ };
2430
+ contextsLoaded += 1;
2431
+ }
2432
+ this.cachedFlagState = { version: cacheVersion, contexts: fresh };
2433
+ this.debug(
2434
+ `Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
2435
+ );
2436
+ };
2437
+ persistContextToCache = (contextStr) => {
2438
+ const checksForContext = this.checks[contextStr];
2439
+ const planForContext = this.planChecks[contextStr];
2440
+ const creditBalancesForContext = this.creditBalances[contextStr];
2441
+ if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
2442
+ return;
2443
+ }
2444
+ if (this.cachedFlagState === null) {
2445
+ this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
2446
+ version: cacheVersion,
2447
+ contexts: {}
2448
+ };
2449
+ }
2450
+ const cleanChecks = {};
2451
+ if (checksForContext !== void 0) {
2452
+ for (const [flagKey, check] of Object.entries(checksForContext)) {
2453
+ if (check !== void 0) cleanChecks[flagKey] = check;
2454
+ }
2455
+ }
2456
+ this.cachedFlagState.contexts[contextStr] = {
2457
+ checks: cleanChecks,
2458
+ plan: planForContext,
2459
+ creditBalances: creditBalancesForContext,
2460
+ updatedAt: Date.now()
2461
+ };
2462
+ const entries = Object.entries(this.cachedFlagState.contexts);
2463
+ if (entries.length > flagStateCacheMaxContexts) {
2464
+ entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
2465
+ const survivors = entries.slice(0, flagStateCacheMaxContexts);
2466
+ const survivorKeys = new Set(survivors.map(([k]) => k));
2467
+ for (const key of Object.keys(this.checks)) {
2468
+ if (!survivorKeys.has(key)) delete this.checks[key];
2469
+ }
2470
+ for (const key of Object.keys(this.planChecks)) {
2471
+ if (!survivorKeys.has(key)) delete this.planChecks[key];
2472
+ }
2473
+ for (const key of Object.keys(this.creditBalances)) {
2474
+ if (!survivorKeys.has(key)) delete this.creditBalances[key];
2475
+ }
2476
+ this.cachedFlagState = {
2477
+ version: cacheVersion,
2478
+ contexts: Object.fromEntries(survivors)
2479
+ };
2480
+ }
2481
+ if (!this.persistFlagState || this.storage === void 0) return;
2482
+ try {
2483
+ this.storage.setItem(
2484
+ this.flagStateCacheKey,
2485
+ JSON.stringify(this.cachedFlagState)
2486
+ );
2487
+ } catch (error) {
2488
+ this.debug("Failed to write flag state cache:", error);
2489
+ }
2490
+ };
1544
2491
  handleEvent = (eventType, eventBody) => {
1545
2492
  const event = {
1546
2493
  api_key: this.apiKey,
@@ -1568,7 +2515,7 @@ var Schematic = class {
1568
2515
  const response = await fetch(captureUrl, {
1569
2516
  method: "POST",
1570
2517
  headers: {
1571
- ...this.additionalHeaders ?? {},
2518
+ ...this._additionalHeaders ?? {},
1572
2519
  "Content-Type": "application/json;charset=UTF-8"
1573
2520
  },
1574
2521
  body: payload
@@ -1801,6 +2748,9 @@ var Schematic = class {
1801
2748
  if (this.conn !== null) {
1802
2749
  try {
1803
2750
  const socket = await this.conn;
2751
+ if (this.currentWebSocket === socket) {
2752
+ this.currentWebSocket = null;
2753
+ }
1804
2754
  if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
1805
2755
  socket.close();
1806
2756
  }
@@ -1966,6 +2916,7 @@ var Schematic = class {
1966
2916
  this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
1967
2917
  let timeoutId = null;
1968
2918
  let isResolved = false;
2919
+ let didOpen = false;
1969
2920
  timeoutId = setTimeout(() => {
1970
2921
  if (!isResolved) {
1971
2922
  isResolved = true;
@@ -1979,6 +2930,7 @@ var Schematic = class {
1979
2930
  webSocket.onopen = () => {
1980
2931
  if (isResolved) return;
1981
2932
  isResolved = true;
2933
+ didOpen = true;
1982
2934
  if (timeoutId !== null) {
1983
2935
  clearTimeout(timeoutId);
1984
2936
  }
@@ -2004,11 +2956,12 @@ var Schematic = class {
2004
2956
  }
2005
2957
  this.debug(`WebSocket connection ${connectionId} closed`);
2006
2958
  this.conn = null;
2959
+ const wasCurrent = this.currentWebSocket === webSocket;
2007
2960
  if (this.currentWebSocket === webSocket) {
2008
2961
  this.currentWebSocket = null;
2009
2962
  this.isConnecting = false;
2010
2963
  }
2011
- if (!isResolved && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
2964
+ if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
2012
2965
  this.attemptReconnect();
2013
2966
  }
2014
2967
  };
@@ -2058,7 +3011,7 @@ var Schematic = class {
2058
3011
  }
2059
3012
  });
2060
3013
  this.currentWebSocket = socket;
2061
- const clientVersion = this.additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
3014
+ const clientVersion = this._additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
2062
3015
  const messagePayload = {
2063
3016
  apiKey: this.apiKey,
2064
3017
  clientVersion,
@@ -2104,6 +3057,16 @@ var Schematic = class {
2104
3057
  const plan = this.planChecks[contextStr];
2105
3058
  return plan;
2106
3059
  };
3060
+ /** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
3061
+ getCreditBalances = () => {
3062
+ const contextStr = contextString(this.context);
3063
+ return this.creditBalances[contextStr] ?? emptyCreditBalances;
3064
+ };
3065
+ /** Get the company's lease-aware balance for a single credit type in the current context */
3066
+ getCreditBalance = (creditId) => {
3067
+ const contextStr = contextString(this.context);
3068
+ return this.creditBalances[contextStr]?.[creditId];
3069
+ };
2107
3070
  // flag checks state
2108
3071
  getFlagCheck = (flagKey) => {
2109
3072
  const contextStr = contextString(this.context);
@@ -2163,6 +3126,13 @@ var Schematic = class {
2163
3126
  this.planListeners.delete(listener);
2164
3127
  };
2165
3128
  };
3129
+ /** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
3130
+ addCreditBalanceListener = (listener) => {
3131
+ this.creditBalanceListeners.add(listener);
3132
+ return () => {
3133
+ this.creditBalanceListeners.delete(listener);
3134
+ };
3135
+ };
2166
3136
  notifyFlagCheckListeners = (flagKey, check) => {
2167
3137
  const listeners = this.flagCheckListeners?.[flagKey] ?? [];
2168
3138
  if (listeners.size > 0) {
@@ -2226,6 +3196,17 @@ var Schematic = class {
2226
3196
  });
2227
3197
  });
2228
3198
  };
3199
+ notifyCreditBalanceListeners = (value) => {
3200
+ const listeners = this.creditBalanceListeners ?? [];
3201
+ if (listeners.size > 0) {
3202
+ this.debug(`Notifying ${listeners.size} credit balance listeners`, {
3203
+ value
3204
+ });
3205
+ }
3206
+ listeners.forEach(
3207
+ (listener) => notifyCreditBalanceListener(listener, value)
3208
+ );
3209
+ };
2229
3210
  };
2230
3211
  var notifyPendingListener = (listener, value) => {
2231
3212
  if (listener.length > 0) {
@@ -2255,15 +3236,22 @@ var notifyPlanListener = (listener, value) => {
2255
3236
  listener();
2256
3237
  }
2257
3238
  };
3239
+ var notifyCreditBalanceListener = (listener, value) => {
3240
+ if (listener.length > 0) {
3241
+ listener(value);
3242
+ } else {
3243
+ listener();
3244
+ }
3245
+ };
2258
3246
 
2259
3247
  // src/context/schematic.ts
2260
3248
  import { inject, onScopeDispose } from "vue";
2261
3249
 
2262
3250
  // src/version.ts
2263
- var version2 = "1.4.1";
3251
+ var version2 = "1.6.0";
2264
3252
 
2265
3253
  // src/context/schematic.ts
2266
- var SchematicSymbol = Symbol("schematic");
3254
+ var SchematicSymbol = /* @__PURE__ */ Symbol("schematic");
2267
3255
  var SchematicPlugin = {
2268
3256
  install(app, options) {
2269
3257
  let client;
@@ -2300,7 +3288,14 @@ var useSchematic = () => {
2300
3288
  };
2301
3289
 
2302
3290
  // src/composables/schematic.ts
2303
- import { computed, onMounted, onScopeDispose as onScopeDispose2, ref } from "vue";
3291
+ import {
3292
+ computed,
3293
+ onMounted,
3294
+ onScopeDispose as onScopeDispose2,
3295
+ ref,
3296
+ toValue,
3297
+ watch
3298
+ } from "vue";
2304
3299
  var useSchematicClient = (opts) => {
2305
3300
  const schematic = useSchematic();
2306
3301
  const { client } = opts ?? {};
@@ -2370,10 +3365,17 @@ var useSchematicEntitlement = (key, opts) => {
2370
3365
  featureUsageExceeded: computed(() => flagCheck.value.featureUsageExceeded),
2371
3366
  featureUsageEvent: computed(() => flagCheck.value.featureUsageEvent),
2372
3367
  featureUsagePeriod: computed(() => flagCheck.value.featureUsagePeriod),
3368
+ softLimit: computed(() => flagCheck.value.softLimit),
3369
+ warningTiers: computed(() => flagCheck.value.warningTiers),
2373
3370
  flagId: computed(() => flagCheck.value.flagId),
2374
3371
  ruleId: computed(() => flagCheck.value.ruleId),
2375
3372
  companyId: computed(() => flagCheck.value.companyId),
2376
- userId: computed(() => flagCheck.value.userId)
3373
+ userId: computed(() => flagCheck.value.userId),
3374
+ // Credit fields, populated for features metered by credit burndown
3375
+ creditId: computed(() => flagCheck.value.creditId),
3376
+ creditSettled: computed(() => flagCheck.value.creditSettled),
3377
+ creditRemaining: computed(() => flagCheck.value.creditRemaining),
3378
+ creditReserved: computed(() => flagCheck.value.creditReserved)
2377
3379
  };
2378
3380
  };
2379
3381
  var useSchematicPlan = (opts) => {
@@ -2393,6 +3395,44 @@ var useSchematicPlan = (opts) => {
2393
3395
  });
2394
3396
  return plan;
2395
3397
  };
3398
+ var useSchematicCreditBalance = (creditId, opts) => {
3399
+ const client = useSchematicClient(opts);
3400
+ const resolvedCreditId = computed(() => toValue(creditId));
3401
+ const readBalance = () => {
3402
+ const id = resolvedCreditId.value;
3403
+ return id === void 0 ? void 0 : client.getCreditBalance(id);
3404
+ };
3405
+ const creditBalance = ref(
3406
+ readBalance()
3407
+ );
3408
+ const isPending = ref(client.getIsPending());
3409
+ watch(resolvedCreditId, () => {
3410
+ creditBalance.value = readBalance();
3411
+ });
3412
+ let unsubscribeBalance = null;
3413
+ let unsubscribePending = null;
3414
+ onMounted(() => {
3415
+ creditBalance.value = readBalance();
3416
+ unsubscribeBalance = client.addCreditBalanceListener(() => {
3417
+ creditBalance.value = readBalance();
3418
+ });
3419
+ unsubscribePending = client.addIsPendingListener(() => {
3420
+ isPending.value = client.getIsPending();
3421
+ });
3422
+ });
3423
+ onScopeDispose2(() => {
3424
+ unsubscribeBalance?.();
3425
+ unsubscribePending?.();
3426
+ });
3427
+ return {
3428
+ /** The spendable balance; 0 while loading or when the company holds no balance in this credit */
3429
+ balance: computed(() => creditBalance.value?.settled ?? 0),
3430
+ /** True while the balance is still loading and no value has arrived yet */
3431
+ isLoading: computed(
3432
+ () => creditBalance.value === void 0 && isPending.value
3433
+ )
3434
+ };
3435
+ };
2396
3436
  var useSchematicIsPending = (opts) => {
2397
3437
  const client = useSchematicClient(opts);
2398
3438
  const isPending = ref(client.getIsPending());
@@ -2415,6 +3455,7 @@ export {
2415
3455
  useSchematic,
2416
3456
  useSchematicClient,
2417
3457
  useSchematicContext,
3458
+ useSchematicCreditBalance,
2418
3459
  useSchematicEntitlement,
2419
3460
  useSchematicEvents,
2420
3461
  useSchematicFlag,