@schematichq/schematic-react 1.4.1 → 1.5.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.
- package/README.md +27 -0
- package/dist/schematic-react.cjs.js +665 -27
- package/dist/schematic-react.d.ts +184 -22
- package/dist/schematic-react.esm.js +665 -27
- package/package.json +16 -16
|
@@ -6,7 +6,11 @@ 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
|
-
|
|
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
|
+
}
|
|
10
14
|
};
|
|
11
15
|
var __copyProps = (to, from, except, desc) => {
|
|
12
16
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -565,19 +569,16 @@ for (let i = 0; i < 256; ++i) {
|
|
|
565
569
|
function unsafeStringify(arr, offset = 0) {
|
|
566
570
|
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
571
|
}
|
|
568
|
-
var getRandomValues;
|
|
569
572
|
var rnds8 = new Uint8Array(16);
|
|
570
573
|
function rng() {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
574
|
+
return crypto.getRandomValues(rnds8);
|
|
575
|
+
}
|
|
576
|
+
function v4(options, buf, offset) {
|
|
577
|
+
if (!buf && !options && crypto.randomUUID) {
|
|
578
|
+
return crypto.randomUUID();
|
|
576
579
|
}
|
|
577
|
-
return
|
|
580
|
+
return _v4(options, buf, offset);
|
|
578
581
|
}
|
|
579
|
-
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
580
|
-
var native_default = { randomUUID };
|
|
581
582
|
function _v4(options, buf, offset) {
|
|
582
583
|
options = options || {};
|
|
583
584
|
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
@@ -598,12 +599,6 @@ function _v4(options, buf, offset) {
|
|
|
598
599
|
}
|
|
599
600
|
return unsafeStringify(rnds);
|
|
600
601
|
}
|
|
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
602
|
var v4_default = v4;
|
|
608
603
|
var import_polyfill = __toESM(require_browser_polyfill());
|
|
609
604
|
function EntitlementValueTypeFromJSON(json) {
|
|
@@ -612,6 +607,18 @@ function EntitlementValueTypeFromJSON(json) {
|
|
|
612
607
|
function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
613
608
|
return json;
|
|
614
609
|
}
|
|
610
|
+
function MetricPeriodMonthResetFromJSON(json) {
|
|
611
|
+
return MetricPeriodMonthResetFromJSONTyped(json, false);
|
|
612
|
+
}
|
|
613
|
+
function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
|
|
614
|
+
return json;
|
|
615
|
+
}
|
|
616
|
+
function MetricPeriodFromJSON(json) {
|
|
617
|
+
return MetricPeriodFromJSONTyped(json, false);
|
|
618
|
+
}
|
|
619
|
+
function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
|
|
620
|
+
return json;
|
|
621
|
+
}
|
|
615
622
|
function FeatureEntitlementFromJSON(json) {
|
|
616
623
|
return FeatureEntitlementFromJSONTyped(json, false);
|
|
617
624
|
}
|
|
@@ -621,21 +628,31 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
621
628
|
}
|
|
622
629
|
return {
|
|
623
630
|
allocation: json["allocation"] == null ? void 0 : json["allocation"],
|
|
631
|
+
consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
|
|
624
632
|
creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
|
|
625
633
|
creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
|
|
634
|
+
creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
|
|
635
|
+
creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
|
|
626
636
|
creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
|
|
627
637
|
creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
|
|
628
638
|
eventName: json["event_name"] == null ? void 0 : json["event_name"],
|
|
639
|
+
eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
|
|
629
640
|
featureId: json["feature_id"],
|
|
630
641
|
featureKey: json["feature_key"],
|
|
631
|
-
metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
|
|
642
|
+
metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
|
|
632
643
|
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"],
|
|
644
|
+
monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
|
|
634
645
|
softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
|
|
635
646
|
usage: json["usage"] == null ? void 0 : json["usage"],
|
|
636
647
|
valueType: EntitlementValueTypeFromJSON(json["value_type"])
|
|
637
648
|
};
|
|
638
649
|
}
|
|
650
|
+
function RuleTypeFromJSON(json) {
|
|
651
|
+
return RuleTypeFromJSONTyped(json, false);
|
|
652
|
+
}
|
|
653
|
+
function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
654
|
+
return json;
|
|
655
|
+
}
|
|
639
656
|
function CheckFlagResponseDataFromJSON(json) {
|
|
640
657
|
return CheckFlagResponseDataFromJSONTyped(json, false);
|
|
641
658
|
}
|
|
@@ -650,13 +667,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
650
667
|
featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
|
|
651
668
|
featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
|
|
652
669
|
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"],
|
|
670
|
+
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
|
|
654
671
|
featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
|
|
655
672
|
flag: json["flag"],
|
|
656
673
|
flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
|
|
657
674
|
reason: json["reason"],
|
|
658
675
|
ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
|
|
659
|
-
ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
|
|
676
|
+
ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
|
|
660
677
|
userId: json["user_id"] == null ? void 0 : json["user_id"],
|
|
661
678
|
value: json["value"]
|
|
662
679
|
};
|
|
@@ -673,6 +690,268 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
673
690
|
params: json["params"]
|
|
674
691
|
};
|
|
675
692
|
}
|
|
693
|
+
var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
|
|
694
|
+
var Configuration = class {
|
|
695
|
+
constructor(configuration = {}) {
|
|
696
|
+
this.configuration = configuration;
|
|
697
|
+
}
|
|
698
|
+
configuration;
|
|
699
|
+
set config(configuration) {
|
|
700
|
+
this.configuration = configuration;
|
|
701
|
+
}
|
|
702
|
+
get basePath() {
|
|
703
|
+
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
|
704
|
+
}
|
|
705
|
+
get fetchApi() {
|
|
706
|
+
return this.configuration.fetchApi;
|
|
707
|
+
}
|
|
708
|
+
get middleware() {
|
|
709
|
+
return this.configuration.middleware || [];
|
|
710
|
+
}
|
|
711
|
+
get queryParamsStringify() {
|
|
712
|
+
return this.configuration.queryParamsStringify || querystring;
|
|
713
|
+
}
|
|
714
|
+
get username() {
|
|
715
|
+
return this.configuration.username;
|
|
716
|
+
}
|
|
717
|
+
get password() {
|
|
718
|
+
return this.configuration.password;
|
|
719
|
+
}
|
|
720
|
+
get apiKey() {
|
|
721
|
+
const apiKey = this.configuration.apiKey;
|
|
722
|
+
if (apiKey) {
|
|
723
|
+
return typeof apiKey === "function" ? apiKey : () => apiKey;
|
|
724
|
+
}
|
|
725
|
+
return void 0;
|
|
726
|
+
}
|
|
727
|
+
get accessToken() {
|
|
728
|
+
const accessToken = this.configuration.accessToken;
|
|
729
|
+
if (accessToken) {
|
|
730
|
+
return typeof accessToken === "function" ? accessToken : async () => accessToken;
|
|
731
|
+
}
|
|
732
|
+
return void 0;
|
|
733
|
+
}
|
|
734
|
+
get headers() {
|
|
735
|
+
return this.configuration.headers;
|
|
736
|
+
}
|
|
737
|
+
get credentials() {
|
|
738
|
+
return this.configuration.credentials;
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
var DefaultConfig = new Configuration();
|
|
742
|
+
var BaseAPI = class _BaseAPI {
|
|
743
|
+
constructor(configuration = DefaultConfig) {
|
|
744
|
+
this.configuration = configuration;
|
|
745
|
+
this.middleware = configuration.middleware;
|
|
746
|
+
}
|
|
747
|
+
configuration;
|
|
748
|
+
static jsonRegex = new RegExp(
|
|
749
|
+
"^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
|
|
750
|
+
"i"
|
|
751
|
+
);
|
|
752
|
+
middleware;
|
|
753
|
+
withMiddleware(...middlewares) {
|
|
754
|
+
const next = this.clone();
|
|
755
|
+
next.middleware = next.middleware.concat(...middlewares);
|
|
756
|
+
return next;
|
|
757
|
+
}
|
|
758
|
+
withPreMiddleware(...preMiddlewares) {
|
|
759
|
+
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
|
760
|
+
return this.withMiddleware(...middlewares);
|
|
761
|
+
}
|
|
762
|
+
withPostMiddleware(...postMiddlewares) {
|
|
763
|
+
const middlewares = postMiddlewares.map((post) => ({ post }));
|
|
764
|
+
return this.withMiddleware(...middlewares);
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Check if the given MIME is a JSON MIME.
|
|
768
|
+
* JSON MIME examples:
|
|
769
|
+
* application/json
|
|
770
|
+
* application/json; charset=UTF8
|
|
771
|
+
* APPLICATION/JSON
|
|
772
|
+
* application/vnd.company+json
|
|
773
|
+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
|
774
|
+
* @return True if the given MIME is JSON, false otherwise.
|
|
775
|
+
*/
|
|
776
|
+
isJsonMime(mime) {
|
|
777
|
+
if (!mime) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
return _BaseAPI.jsonRegex.test(mime);
|
|
781
|
+
}
|
|
782
|
+
async request(context, initOverrides) {
|
|
783
|
+
const { url, init } = await this.createFetchParams(context, initOverrides);
|
|
784
|
+
const response = await this.fetchApi(url, init);
|
|
785
|
+
if (response && response.status >= 200 && response.status < 300) {
|
|
786
|
+
return response;
|
|
787
|
+
}
|
|
788
|
+
throw new ResponseError(response, "Response returned an error code");
|
|
789
|
+
}
|
|
790
|
+
async createFetchParams(context, initOverrides) {
|
|
791
|
+
let url = this.configuration.basePath + context.path;
|
|
792
|
+
if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
|
|
793
|
+
url += "?" + this.configuration.queryParamsStringify(context.query);
|
|
794
|
+
}
|
|
795
|
+
const headers = Object.assign(
|
|
796
|
+
{},
|
|
797
|
+
this.configuration.headers,
|
|
798
|
+
context.headers
|
|
799
|
+
);
|
|
800
|
+
Object.keys(headers).forEach(
|
|
801
|
+
(key) => headers[key] === void 0 ? delete headers[key] : {}
|
|
802
|
+
);
|
|
803
|
+
const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
|
|
804
|
+
const initParams = {
|
|
805
|
+
method: context.method,
|
|
806
|
+
headers,
|
|
807
|
+
body: context.body,
|
|
808
|
+
credentials: this.configuration.credentials
|
|
809
|
+
};
|
|
810
|
+
const overriddenInit = {
|
|
811
|
+
...initParams,
|
|
812
|
+
...await initOverrideFn({
|
|
813
|
+
init: initParams,
|
|
814
|
+
context
|
|
815
|
+
})
|
|
816
|
+
};
|
|
817
|
+
let body;
|
|
818
|
+
if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
|
|
819
|
+
body = overriddenInit.body;
|
|
820
|
+
} else if (this.isJsonMime(headers["Content-Type"])) {
|
|
821
|
+
body = JSON.stringify(overriddenInit.body);
|
|
822
|
+
} else {
|
|
823
|
+
body = overriddenInit.body;
|
|
824
|
+
}
|
|
825
|
+
const init = {
|
|
826
|
+
...overriddenInit,
|
|
827
|
+
body
|
|
828
|
+
};
|
|
829
|
+
return { url, init };
|
|
830
|
+
}
|
|
831
|
+
fetchApi = async (url, init) => {
|
|
832
|
+
let fetchParams = { url, init };
|
|
833
|
+
for (const middleware of this.middleware) {
|
|
834
|
+
if (middleware.pre) {
|
|
835
|
+
fetchParams = await middleware.pre({
|
|
836
|
+
fetch: this.fetchApi,
|
|
837
|
+
...fetchParams
|
|
838
|
+
}) || fetchParams;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
let response = void 0;
|
|
842
|
+
try {
|
|
843
|
+
response = await (this.configuration.fetchApi || fetch)(
|
|
844
|
+
fetchParams.url,
|
|
845
|
+
fetchParams.init
|
|
846
|
+
);
|
|
847
|
+
} catch (e) {
|
|
848
|
+
for (const middleware of this.middleware) {
|
|
849
|
+
if (middleware.onError) {
|
|
850
|
+
response = await middleware.onError({
|
|
851
|
+
fetch: this.fetchApi,
|
|
852
|
+
url: fetchParams.url,
|
|
853
|
+
init: fetchParams.init,
|
|
854
|
+
error: e,
|
|
855
|
+
response: response ? response.clone() : void 0
|
|
856
|
+
}) || response;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (response === void 0) {
|
|
860
|
+
if (e instanceof Error) {
|
|
861
|
+
throw new FetchError(
|
|
862
|
+
e,
|
|
863
|
+
"The request failed and the interceptors did not return an alternative response"
|
|
864
|
+
);
|
|
865
|
+
} else {
|
|
866
|
+
throw e;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
for (const middleware of this.middleware) {
|
|
871
|
+
if (middleware.post) {
|
|
872
|
+
response = await middleware.post({
|
|
873
|
+
fetch: this.fetchApi,
|
|
874
|
+
url: fetchParams.url,
|
|
875
|
+
init: fetchParams.init,
|
|
876
|
+
response: response.clone()
|
|
877
|
+
}) || response;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return response;
|
|
881
|
+
};
|
|
882
|
+
/**
|
|
883
|
+
* Create a shallow clone of `this` by constructing a new instance
|
|
884
|
+
* and then shallow cloning data members.
|
|
885
|
+
*/
|
|
886
|
+
clone() {
|
|
887
|
+
const constructor = this.constructor;
|
|
888
|
+
const next = new constructor(this.configuration);
|
|
889
|
+
next.middleware = this.middleware.slice();
|
|
890
|
+
return next;
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
function isBlob(value) {
|
|
894
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
895
|
+
}
|
|
896
|
+
function isFormData(value) {
|
|
897
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
898
|
+
}
|
|
899
|
+
var ResponseError = class extends Error {
|
|
900
|
+
constructor(response, msg) {
|
|
901
|
+
super(msg);
|
|
902
|
+
this.response = response;
|
|
903
|
+
}
|
|
904
|
+
response;
|
|
905
|
+
name = "ResponseError";
|
|
906
|
+
};
|
|
907
|
+
var FetchError = class extends Error {
|
|
908
|
+
constructor(cause, msg) {
|
|
909
|
+
super(msg);
|
|
910
|
+
this.cause = cause;
|
|
911
|
+
}
|
|
912
|
+
cause;
|
|
913
|
+
name = "FetchError";
|
|
914
|
+
};
|
|
915
|
+
function querystring(params, prefix = "") {
|
|
916
|
+
return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
|
|
917
|
+
}
|
|
918
|
+
function querystringSingleKey(key, value, keyPrefix = "") {
|
|
919
|
+
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
|
920
|
+
if (value instanceof Array) {
|
|
921
|
+
const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
|
|
922
|
+
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
|
923
|
+
}
|
|
924
|
+
if (value instanceof Set) {
|
|
925
|
+
const valueAsArray = Array.from(value);
|
|
926
|
+
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
|
927
|
+
}
|
|
928
|
+
if (value instanceof Date) {
|
|
929
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
|
930
|
+
}
|
|
931
|
+
if (value instanceof Object) {
|
|
932
|
+
return querystring(value, fullKey);
|
|
933
|
+
}
|
|
934
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
|
935
|
+
}
|
|
936
|
+
function mapValues(data, fn) {
|
|
937
|
+
return Object.keys(data).reduce(
|
|
938
|
+
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
|
939
|
+
{}
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
function CompanyCreditBalanceFromJSON(json) {
|
|
943
|
+
return CompanyCreditBalanceFromJSONTyped(json, false);
|
|
944
|
+
}
|
|
945
|
+
function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
|
|
946
|
+
if (json == null) {
|
|
947
|
+
return json;
|
|
948
|
+
}
|
|
949
|
+
return {
|
|
950
|
+
remaining: json["remaining"],
|
|
951
|
+
reserved: json["reserved"],
|
|
952
|
+
settled: json["settled"]
|
|
953
|
+
};
|
|
954
|
+
}
|
|
676
955
|
var TrialStatus = {
|
|
677
956
|
Active: "active",
|
|
678
957
|
Converted: "converted",
|
|
@@ -706,6 +985,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
706
985
|
return json;
|
|
707
986
|
}
|
|
708
987
|
return {
|
|
988
|
+
creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
|
|
709
989
|
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
710
990
|
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
711
991
|
};
|
|
@@ -788,7 +1068,10 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
788
1068
|
return {
|
|
789
1069
|
featureUsageExceeded,
|
|
790
1070
|
companyId: companyId == null ? void 0 : companyId,
|
|
1071
|
+
creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
|
|
791
1072
|
creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
|
|
1073
|
+
creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
|
|
1074
|
+
creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
|
|
792
1075
|
error: error == null ? void 0 : error,
|
|
793
1076
|
featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
|
|
794
1077
|
featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
|
|
@@ -814,6 +1097,22 @@ var CheckPlanReturnFromJSON = (json) => {
|
|
|
814
1097
|
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
815
1098
|
};
|
|
816
1099
|
};
|
|
1100
|
+
var CreditBalancesFromJSON = (json) => {
|
|
1101
|
+
if (json == null || typeof json !== "object") {
|
|
1102
|
+
return {};
|
|
1103
|
+
}
|
|
1104
|
+
const balances = {};
|
|
1105
|
+
for (const [creditId, raw] of Object.entries(json)) {
|
|
1106
|
+
if (raw == null || typeof raw !== "object") continue;
|
|
1107
|
+
const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
|
|
1108
|
+
if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
balances[creditId] = { remaining, reserved, settled };
|
|
1112
|
+
}
|
|
1113
|
+
return balances;
|
|
1114
|
+
};
|
|
1115
|
+
var cacheVersion = "bb56e75d";
|
|
817
1116
|
function contextString(context) {
|
|
818
1117
|
const sortedContext = Object.keys(context).reduce((acc, key) => {
|
|
819
1118
|
const sortedKeys = Object.keys(
|
|
@@ -828,8 +1127,12 @@ function contextString(context) {
|
|
|
828
1127
|
}, {});
|
|
829
1128
|
return JSON.stringify(sortedContext);
|
|
830
1129
|
}
|
|
831
|
-
var version = "1.
|
|
1130
|
+
var version = "1.5.0";
|
|
832
1131
|
var anonymousIdKey = "schematicId";
|
|
1132
|
+
var flagStateCachePrefix = "schematicCache";
|
|
1133
|
+
var flagStateCacheMaxContexts = 10;
|
|
1134
|
+
var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1135
|
+
var emptyCreditBalances = Object.freeze({});
|
|
833
1136
|
var Schematic = class {
|
|
834
1137
|
additionalHeaders = {};
|
|
835
1138
|
apiKey;
|
|
@@ -846,11 +1149,17 @@ var Schematic = class {
|
|
|
846
1149
|
isPending = true;
|
|
847
1150
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
848
1151
|
planListeners = /* @__PURE__ */ new Set();
|
|
1152
|
+
creditBalanceListeners = /* @__PURE__ */ new Set();
|
|
849
1153
|
storage;
|
|
1154
|
+
persistFlagState = true;
|
|
1155
|
+
flagStateCacheKey;
|
|
1156
|
+
flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
|
|
1157
|
+
cachedFlagState = null;
|
|
850
1158
|
useWebSocket = false;
|
|
851
1159
|
checks = {};
|
|
852
1160
|
featureUsageEventMap = {};
|
|
853
1161
|
planChecks = {};
|
|
1162
|
+
creditBalances = {};
|
|
854
1163
|
webSocketUrl = "wss://api.schematichq.com";
|
|
855
1164
|
webSocketConnectionTimeout = 1e4;
|
|
856
1165
|
webSocketReconnect = true;
|
|
@@ -879,11 +1188,16 @@ var Schematic = class {
|
|
|
879
1188
|
fallbackCheckCache = {};
|
|
880
1189
|
constructor(apiKey, options) {
|
|
881
1190
|
this.apiKey = apiKey;
|
|
1191
|
+
this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
|
|
882
1192
|
this.eventQueue = [];
|
|
883
1193
|
this.contextDependentEventQueue = [];
|
|
884
1194
|
this.useWebSocket = options?.useWebSocket ?? false;
|
|
885
1195
|
this.debugEnabled = options?.debug ?? false;
|
|
886
1196
|
this.offlineEnabled = options?.offline ?? false;
|
|
1197
|
+
this.persistFlagState = options?.persistFlagState ?? true;
|
|
1198
|
+
if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
|
|
1199
|
+
this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
|
|
1200
|
+
}
|
|
887
1201
|
if (typeof window !== "undefined" && typeof window.location !== "undefined") {
|
|
888
1202
|
const params = new URLSearchParams(window.location.search);
|
|
889
1203
|
const debugParam = params.get("schematic_debug");
|
|
@@ -916,6 +1230,7 @@ var Schematic = class {
|
|
|
916
1230
|
} catch {
|
|
917
1231
|
}
|
|
918
1232
|
}
|
|
1233
|
+
this.hydrateFlagStateFromCache();
|
|
919
1234
|
if (options?.apiUrl !== void 0) {
|
|
920
1235
|
this.apiUrl = options.apiUrl;
|
|
921
1236
|
}
|
|
@@ -1209,6 +1524,29 @@ var Schematic = class {
|
|
|
1209
1524
|
});
|
|
1210
1525
|
this.notifyPlanListeners(plan);
|
|
1211
1526
|
}
|
|
1527
|
+
if (message.credit_balances !== void 0 && message.credit_balances !== null) {
|
|
1528
|
+
const contextStr = contextString(context);
|
|
1529
|
+
const updates = CreditBalancesFromJSON(message.credit_balances);
|
|
1530
|
+
const previous = this.creditBalances[contextStr] ?? {};
|
|
1531
|
+
let changed = false;
|
|
1532
|
+
const merged = { ...previous };
|
|
1533
|
+
for (const [creditId, next] of Object.entries(updates)) {
|
|
1534
|
+
const current = previous[creditId];
|
|
1535
|
+
if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
|
|
1536
|
+
merged[creditId] = next;
|
|
1537
|
+
changed = true;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
if (changed) {
|
|
1541
|
+
this.creditBalances[contextStr] = merged;
|
|
1542
|
+
this.debug(
|
|
1543
|
+
`WebSocket credit balance update received. Notifying listeners`,
|
|
1544
|
+
{ creditBalances: merged }
|
|
1545
|
+
);
|
|
1546
|
+
this.notifyCreditBalanceListeners(merged);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
this.persistContextToCache(contextString(context));
|
|
1212
1550
|
this.flushContextDependentEventQueue();
|
|
1213
1551
|
this.setIsPending(false);
|
|
1214
1552
|
};
|
|
@@ -1316,7 +1654,32 @@ var Schematic = class {
|
|
|
1316
1654
|
return;
|
|
1317
1655
|
}
|
|
1318
1656
|
try {
|
|
1319
|
-
|
|
1657
|
+
const newContextStr = contextString(context);
|
|
1658
|
+
const cacheHit = this.hasCachedValuesForContext(newContextStr);
|
|
1659
|
+
if (cacheHit) {
|
|
1660
|
+
this.debug(
|
|
1661
|
+
`setContext: cache hit for context, pre-resolving from cached values`
|
|
1662
|
+
);
|
|
1663
|
+
this.context = context;
|
|
1664
|
+
this.flushContextDependentEventQueue();
|
|
1665
|
+
this.setIsPending(false);
|
|
1666
|
+
const cachedChecks = this.checks[newContextStr] ?? {};
|
|
1667
|
+
for (const [flagKey, check] of Object.entries(cachedChecks)) {
|
|
1668
|
+
if (check === void 0) continue;
|
|
1669
|
+
this.notifyFlagCheckListeners(flagKey, check);
|
|
1670
|
+
this.notifyFlagValueListeners(flagKey, check.value);
|
|
1671
|
+
}
|
|
1672
|
+
const cachedPlan = this.planChecks[newContextStr];
|
|
1673
|
+
if (cachedPlan !== void 0) {
|
|
1674
|
+
this.notifyPlanListeners(cachedPlan);
|
|
1675
|
+
}
|
|
1676
|
+
const cachedCreditBalances = this.creditBalances[newContextStr];
|
|
1677
|
+
if (cachedCreditBalances !== void 0) {
|
|
1678
|
+
this.notifyCreditBalanceListeners(cachedCreditBalances);
|
|
1679
|
+
}
|
|
1680
|
+
} else {
|
|
1681
|
+
this.setIsPending(true);
|
|
1682
|
+
}
|
|
1320
1683
|
if (!this.conn) {
|
|
1321
1684
|
if (this.isConnecting) {
|
|
1322
1685
|
this.debug(
|
|
@@ -1327,7 +1690,7 @@ var Schematic = class {
|
|
|
1327
1690
|
}
|
|
1328
1691
|
if (this.conn !== null) {
|
|
1329
1692
|
const socket2 = await this.conn;
|
|
1330
|
-
await this.wsSendMessage(socket2, context);
|
|
1693
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1331
1694
|
return;
|
|
1332
1695
|
}
|
|
1333
1696
|
}
|
|
@@ -1343,7 +1706,7 @@ var Schematic = class {
|
|
|
1343
1706
|
this.conn = this.wsConnect();
|
|
1344
1707
|
const socket2 = await this.conn;
|
|
1345
1708
|
this.isConnecting = false;
|
|
1346
|
-
await this.wsSendMessage(socket2, context);
|
|
1709
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1347
1710
|
return;
|
|
1348
1711
|
} catch (error) {
|
|
1349
1712
|
this.isConnecting = false;
|
|
@@ -1351,7 +1714,7 @@ var Schematic = class {
|
|
|
1351
1714
|
}
|
|
1352
1715
|
}
|
|
1353
1716
|
const socket = await this.conn;
|
|
1354
|
-
await this.wsSendMessage(socket, context);
|
|
1717
|
+
await this.wsSendMessage(socket, context, cacheHit);
|
|
1355
1718
|
} catch (error) {
|
|
1356
1719
|
console.warn("Failed to establish WebSocket connection:", error);
|
|
1357
1720
|
this.context = context;
|
|
@@ -1411,10 +1774,12 @@ var Schematic = class {
|
|
|
1411
1774
|
`Optimistically updating feature usage for event: ${eventName}`,
|
|
1412
1775
|
{ quantity }
|
|
1413
1776
|
);
|
|
1777
|
+
let dirty = false;
|
|
1414
1778
|
Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
|
|
1415
1779
|
if (check === void 0) return;
|
|
1416
1780
|
const updatedCheck = { ...check };
|
|
1417
1781
|
if (typeof updatedCheck.featureUsage === "number") {
|
|
1782
|
+
dirty = true;
|
|
1418
1783
|
updatedCheck.featureUsage += quantity;
|
|
1419
1784
|
if (typeof updatedCheck.featureAllocation === "number") {
|
|
1420
1785
|
const wasExceeded = updatedCheck.featureUsageExceeded === true;
|
|
@@ -1444,6 +1809,9 @@ var Schematic = class {
|
|
|
1444
1809
|
this.notifyFlagValueListeners(flagKey, updatedCheck.value);
|
|
1445
1810
|
}
|
|
1446
1811
|
});
|
|
1812
|
+
if (dirty) {
|
|
1813
|
+
this.persistContextToCache(contextString(this.context));
|
|
1814
|
+
}
|
|
1447
1815
|
};
|
|
1448
1816
|
/**
|
|
1449
1817
|
* Event processing
|
|
@@ -1546,6 +1914,206 @@ var Schematic = class {
|
|
|
1546
1914
|
this.storage.setItem(anonymousIdKey, generatedAnonymousId);
|
|
1547
1915
|
return generatedAnonymousId;
|
|
1548
1916
|
};
|
|
1917
|
+
hasCachedValuesForContext = (contextStr) => {
|
|
1918
|
+
const cachedChecks = this.checks[contextStr];
|
|
1919
|
+
if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
|
|
1920
|
+
return true;
|
|
1921
|
+
}
|
|
1922
|
+
if (this.planChecks[contextStr] !== void 0) {
|
|
1923
|
+
return true;
|
|
1924
|
+
}
|
|
1925
|
+
const cachedCreditBalances = this.creditBalances[contextStr];
|
|
1926
|
+
return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
|
|
1927
|
+
};
|
|
1928
|
+
readFlagStateCache = () => {
|
|
1929
|
+
if (!this.persistFlagState || this.storage === void 0) {
|
|
1930
|
+
return null;
|
|
1931
|
+
}
|
|
1932
|
+
let raw;
|
|
1933
|
+
try {
|
|
1934
|
+
raw = this.storage.getItem(this.flagStateCacheKey);
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
this.debug("Failed to read flag state cache:", error);
|
|
1937
|
+
return null;
|
|
1938
|
+
}
|
|
1939
|
+
if (raw === null || raw === void 0) {
|
|
1940
|
+
return null;
|
|
1941
|
+
}
|
|
1942
|
+
let parsed;
|
|
1943
|
+
try {
|
|
1944
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1945
|
+
} catch (error) {
|
|
1946
|
+
this.debug("Flag state cache is not valid JSON, ignoring:", error);
|
|
1947
|
+
return null;
|
|
1948
|
+
}
|
|
1949
|
+
if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
|
|
1950
|
+
this.debug(
|
|
1951
|
+
`Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
|
|
1952
|
+
{
|
|
1953
|
+
parsedType: typeof parsed,
|
|
1954
|
+
version: parsed?.version
|
|
1955
|
+
}
|
|
1956
|
+
);
|
|
1957
|
+
return null;
|
|
1958
|
+
}
|
|
1959
|
+
return parsed;
|
|
1960
|
+
};
|
|
1961
|
+
reviveCachedCheck = (raw) => {
|
|
1962
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
1963
|
+
const obj = raw;
|
|
1964
|
+
if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
|
|
1965
|
+
return null;
|
|
1966
|
+
}
|
|
1967
|
+
const revived = { ...obj };
|
|
1968
|
+
if (typeof revived.featureUsageResetAt === "string") {
|
|
1969
|
+
const d = new Date(revived.featureUsageResetAt);
|
|
1970
|
+
revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
|
|
1971
|
+
}
|
|
1972
|
+
return revived;
|
|
1973
|
+
};
|
|
1974
|
+
reviveCachedPlan = (raw) => {
|
|
1975
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
1976
|
+
const obj = raw;
|
|
1977
|
+
if (typeof obj.id !== "string" || typeof obj.name !== "string") {
|
|
1978
|
+
return null;
|
|
1979
|
+
}
|
|
1980
|
+
const revived = { ...obj };
|
|
1981
|
+
if (typeof revived.trialEndDate === "string") {
|
|
1982
|
+
const d = new Date(revived.trialEndDate);
|
|
1983
|
+
revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
|
|
1984
|
+
}
|
|
1985
|
+
return revived;
|
|
1986
|
+
};
|
|
1987
|
+
reviveCachedCreditBalances = (raw) => {
|
|
1988
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
1989
|
+
const revived = {};
|
|
1990
|
+
for (const [creditId, value] of Object.entries(
|
|
1991
|
+
raw
|
|
1992
|
+
)) {
|
|
1993
|
+
if (value === null || typeof value !== "object") continue;
|
|
1994
|
+
const obj = value;
|
|
1995
|
+
if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
revived[creditId] = {
|
|
1999
|
+
remaining: obj.remaining,
|
|
2000
|
+
reserved: obj.reserved,
|
|
2001
|
+
settled: obj.settled
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
return Object.keys(revived).length > 0 ? revived : null;
|
|
2005
|
+
};
|
|
2006
|
+
hydrateFlagStateFromCache = () => {
|
|
2007
|
+
const parsed = this.readFlagStateCache();
|
|
2008
|
+
if (parsed === null) return;
|
|
2009
|
+
const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
|
|
2010
|
+
const fresh = {};
|
|
2011
|
+
let contextsLoaded = 0;
|
|
2012
|
+
let contextsExpired = 0;
|
|
2013
|
+
for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
|
|
2014
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2015
|
+
if (typeof entry.updatedAt !== "number") continue;
|
|
2016
|
+
if (entry.updatedAt < cutoff) {
|
|
2017
|
+
contextsExpired += 1;
|
|
2018
|
+
continue;
|
|
2019
|
+
}
|
|
2020
|
+
const revivedChecks = {};
|
|
2021
|
+
if (entry.checks !== null && typeof entry.checks === "object") {
|
|
2022
|
+
for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
|
|
2023
|
+
const revived = this.reviveCachedCheck(rawCheck);
|
|
2024
|
+
if (revived === null || revived.flag !== flagKey) continue;
|
|
2025
|
+
revivedChecks[flagKey] = revived;
|
|
2026
|
+
if (typeof revived.featureUsageEvent === "string") {
|
|
2027
|
+
this.updateFeatureUsageEventMap(revived);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
if (Object.keys(revivedChecks).length > 0) {
|
|
2031
|
+
this.checks[contextStr] = revivedChecks;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
let revivedPlan;
|
|
2035
|
+
if (entry.plan !== void 0 && entry.plan !== null) {
|
|
2036
|
+
const p = this.reviveCachedPlan(entry.plan);
|
|
2037
|
+
if (p !== null) {
|
|
2038
|
+
revivedPlan = p;
|
|
2039
|
+
this.planChecks[contextStr] = p;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
let revivedCreditBalances;
|
|
2043
|
+
if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
|
|
2044
|
+
const balances = this.reviveCachedCreditBalances(entry.creditBalances);
|
|
2045
|
+
if (balances !== null) {
|
|
2046
|
+
revivedCreditBalances = balances;
|
|
2047
|
+
this.creditBalances[contextStr] = balances;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
fresh[contextStr] = {
|
|
2051
|
+
checks: revivedChecks,
|
|
2052
|
+
plan: revivedPlan,
|
|
2053
|
+
creditBalances: revivedCreditBalances,
|
|
2054
|
+
updatedAt: entry.updatedAt
|
|
2055
|
+
};
|
|
2056
|
+
contextsLoaded += 1;
|
|
2057
|
+
}
|
|
2058
|
+
this.cachedFlagState = { version: cacheVersion, contexts: fresh };
|
|
2059
|
+
this.debug(
|
|
2060
|
+
`Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
|
|
2061
|
+
);
|
|
2062
|
+
};
|
|
2063
|
+
persistContextToCache = (contextStr) => {
|
|
2064
|
+
const checksForContext = this.checks[contextStr];
|
|
2065
|
+
const planForContext = this.planChecks[contextStr];
|
|
2066
|
+
const creditBalancesForContext = this.creditBalances[contextStr];
|
|
2067
|
+
if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
if (this.cachedFlagState === null) {
|
|
2071
|
+
this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
|
|
2072
|
+
version: cacheVersion,
|
|
2073
|
+
contexts: {}
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
const cleanChecks = {};
|
|
2077
|
+
if (checksForContext !== void 0) {
|
|
2078
|
+
for (const [flagKey, check] of Object.entries(checksForContext)) {
|
|
2079
|
+
if (check !== void 0) cleanChecks[flagKey] = check;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
this.cachedFlagState.contexts[contextStr] = {
|
|
2083
|
+
checks: cleanChecks,
|
|
2084
|
+
plan: planForContext,
|
|
2085
|
+
creditBalances: creditBalancesForContext,
|
|
2086
|
+
updatedAt: Date.now()
|
|
2087
|
+
};
|
|
2088
|
+
const entries = Object.entries(this.cachedFlagState.contexts);
|
|
2089
|
+
if (entries.length > flagStateCacheMaxContexts) {
|
|
2090
|
+
entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
|
2091
|
+
const survivors = entries.slice(0, flagStateCacheMaxContexts);
|
|
2092
|
+
const survivorKeys = new Set(survivors.map(([k]) => k));
|
|
2093
|
+
for (const key of Object.keys(this.checks)) {
|
|
2094
|
+
if (!survivorKeys.has(key)) delete this.checks[key];
|
|
2095
|
+
}
|
|
2096
|
+
for (const key of Object.keys(this.planChecks)) {
|
|
2097
|
+
if (!survivorKeys.has(key)) delete this.planChecks[key];
|
|
2098
|
+
}
|
|
2099
|
+
for (const key of Object.keys(this.creditBalances)) {
|
|
2100
|
+
if (!survivorKeys.has(key)) delete this.creditBalances[key];
|
|
2101
|
+
}
|
|
2102
|
+
this.cachedFlagState = {
|
|
2103
|
+
version: cacheVersion,
|
|
2104
|
+
contexts: Object.fromEntries(survivors)
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
if (!this.persistFlagState || this.storage === void 0) return;
|
|
2108
|
+
try {
|
|
2109
|
+
this.storage.setItem(
|
|
2110
|
+
this.flagStateCacheKey,
|
|
2111
|
+
JSON.stringify(this.cachedFlagState)
|
|
2112
|
+
);
|
|
2113
|
+
} catch (error) {
|
|
2114
|
+
this.debug("Failed to write flag state cache:", error);
|
|
2115
|
+
}
|
|
2116
|
+
};
|
|
1549
2117
|
handleEvent = (eventType, eventBody) => {
|
|
1550
2118
|
const event = {
|
|
1551
2119
|
api_key: this.apiKey,
|
|
@@ -1806,6 +2374,9 @@ var Schematic = class {
|
|
|
1806
2374
|
if (this.conn !== null) {
|
|
1807
2375
|
try {
|
|
1808
2376
|
const socket = await this.conn;
|
|
2377
|
+
if (this.currentWebSocket === socket) {
|
|
2378
|
+
this.currentWebSocket = null;
|
|
2379
|
+
}
|
|
1809
2380
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
1810
2381
|
socket.close();
|
|
1811
2382
|
}
|
|
@@ -1971,6 +2542,7 @@ var Schematic = class {
|
|
|
1971
2542
|
this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
|
|
1972
2543
|
let timeoutId = null;
|
|
1973
2544
|
let isResolved = false;
|
|
2545
|
+
let didOpen = false;
|
|
1974
2546
|
timeoutId = setTimeout(() => {
|
|
1975
2547
|
if (!isResolved) {
|
|
1976
2548
|
isResolved = true;
|
|
@@ -1984,6 +2556,7 @@ var Schematic = class {
|
|
|
1984
2556
|
webSocket.onopen = () => {
|
|
1985
2557
|
if (isResolved) return;
|
|
1986
2558
|
isResolved = true;
|
|
2559
|
+
didOpen = true;
|
|
1987
2560
|
if (timeoutId !== null) {
|
|
1988
2561
|
clearTimeout(timeoutId);
|
|
1989
2562
|
}
|
|
@@ -2009,11 +2582,12 @@ var Schematic = class {
|
|
|
2009
2582
|
}
|
|
2010
2583
|
this.debug(`WebSocket connection ${connectionId} closed`);
|
|
2011
2584
|
this.conn = null;
|
|
2585
|
+
const wasCurrent = this.currentWebSocket === webSocket;
|
|
2012
2586
|
if (this.currentWebSocket === webSocket) {
|
|
2013
2587
|
this.currentWebSocket = null;
|
|
2014
2588
|
this.isConnecting = false;
|
|
2015
2589
|
}
|
|
2016
|
-
if (
|
|
2590
|
+
if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
|
|
2017
2591
|
this.attemptReconnect();
|
|
2018
2592
|
}
|
|
2019
2593
|
};
|
|
@@ -2109,6 +2683,16 @@ var Schematic = class {
|
|
|
2109
2683
|
const plan = this.planChecks[contextStr];
|
|
2110
2684
|
return plan;
|
|
2111
2685
|
};
|
|
2686
|
+
/** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
|
|
2687
|
+
getCreditBalances = () => {
|
|
2688
|
+
const contextStr = contextString(this.context);
|
|
2689
|
+
return this.creditBalances[contextStr] ?? emptyCreditBalances;
|
|
2690
|
+
};
|
|
2691
|
+
/** Get the company's lease-aware balance for a single credit type in the current context */
|
|
2692
|
+
getCreditBalance = (creditId) => {
|
|
2693
|
+
const contextStr = contextString(this.context);
|
|
2694
|
+
return this.creditBalances[contextStr]?.[creditId];
|
|
2695
|
+
};
|
|
2112
2696
|
// flag checks state
|
|
2113
2697
|
getFlagCheck = (flagKey) => {
|
|
2114
2698
|
const contextStr = contextString(this.context);
|
|
@@ -2168,6 +2752,13 @@ var Schematic = class {
|
|
|
2168
2752
|
this.planListeners.delete(listener);
|
|
2169
2753
|
};
|
|
2170
2754
|
};
|
|
2755
|
+
/** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
|
|
2756
|
+
addCreditBalanceListener = (listener) => {
|
|
2757
|
+
this.creditBalanceListeners.add(listener);
|
|
2758
|
+
return () => {
|
|
2759
|
+
this.creditBalanceListeners.delete(listener);
|
|
2760
|
+
};
|
|
2761
|
+
};
|
|
2171
2762
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2172
2763
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2173
2764
|
if (listeners.size > 0) {
|
|
@@ -2231,6 +2822,17 @@ var Schematic = class {
|
|
|
2231
2822
|
});
|
|
2232
2823
|
});
|
|
2233
2824
|
};
|
|
2825
|
+
notifyCreditBalanceListeners = (value) => {
|
|
2826
|
+
const listeners = this.creditBalanceListeners ?? [];
|
|
2827
|
+
if (listeners.size > 0) {
|
|
2828
|
+
this.debug(`Notifying ${listeners.size} credit balance listeners`, {
|
|
2829
|
+
value
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
listeners.forEach(
|
|
2833
|
+
(listener) => notifyCreditBalanceListener(listener, value)
|
|
2834
|
+
);
|
|
2835
|
+
};
|
|
2234
2836
|
};
|
|
2235
2837
|
var notifyPendingListener = (listener, value) => {
|
|
2236
2838
|
if (listener.length > 0) {
|
|
@@ -2260,12 +2862,19 @@ var notifyPlanListener = (listener, value) => {
|
|
|
2260
2862
|
listener();
|
|
2261
2863
|
}
|
|
2262
2864
|
};
|
|
2865
|
+
var notifyCreditBalanceListener = (listener, value) => {
|
|
2866
|
+
if (listener.length > 0) {
|
|
2867
|
+
listener(value);
|
|
2868
|
+
} else {
|
|
2869
|
+
listener();
|
|
2870
|
+
}
|
|
2871
|
+
};
|
|
2263
2872
|
|
|
2264
2873
|
// src/context/schematic.tsx
|
|
2265
2874
|
import React, { createContext, useEffect, useMemo, useRef } from "react";
|
|
2266
2875
|
|
|
2267
2876
|
// src/version.ts
|
|
2268
|
-
var version2 = "1.
|
|
2877
|
+
var version2 = "1.5.0";
|
|
2269
2878
|
|
|
2270
2879
|
// src/context/schematic.tsx
|
|
2271
2880
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -2408,6 +3017,34 @@ var useSchematicPlan = (opts) => {
|
|
|
2408
3017
|
}, [client, fallbackPlan]);
|
|
2409
3018
|
return useSyncExternalStore(subscribe, getSnapshot, () => fallbackPlan);
|
|
2410
3019
|
};
|
|
3020
|
+
var useSchematicCreditBalance = (creditId, opts) => {
|
|
3021
|
+
const client = useSchematicClient(opts);
|
|
3022
|
+
const subscribe = useCallback(
|
|
3023
|
+
(callback) => client.addCreditBalanceListener(callback),
|
|
3024
|
+
[client]
|
|
3025
|
+
);
|
|
3026
|
+
const getSnapshot = useCallback(
|
|
3027
|
+
() => client.getCreditBalance(creditId),
|
|
3028
|
+
[client, creditId]
|
|
3029
|
+
);
|
|
3030
|
+
const balance = useSyncExternalStore(subscribe, getSnapshot, () => void 0);
|
|
3031
|
+
const isPendingSubscribe = useCallback(
|
|
3032
|
+
(callback) => client.addIsPendingListener(callback),
|
|
3033
|
+
[client]
|
|
3034
|
+
);
|
|
3035
|
+
const isPending = useSyncExternalStore(
|
|
3036
|
+
isPendingSubscribe,
|
|
3037
|
+
() => client.getIsPending(),
|
|
3038
|
+
() => true
|
|
3039
|
+
);
|
|
3040
|
+
return useMemo2(
|
|
3041
|
+
() => ({
|
|
3042
|
+
balance: balance?.settled ?? 0,
|
|
3043
|
+
isLoading: balance === void 0 && isPending
|
|
3044
|
+
}),
|
|
3045
|
+
[balance, isPending]
|
|
3046
|
+
);
|
|
3047
|
+
};
|
|
2411
3048
|
var useSchematicIsPending = (opts) => {
|
|
2412
3049
|
const client = useSchematicClient(opts);
|
|
2413
3050
|
const subscribe = useCallback(
|
|
@@ -2425,6 +3062,7 @@ export {
|
|
|
2425
3062
|
UsagePeriod,
|
|
2426
3063
|
useSchematic,
|
|
2427
3064
|
useSchematicContext,
|
|
3065
|
+
useSchematicCreditBalance,
|
|
2428
3066
|
useSchematicEntitlement,
|
|
2429
3067
|
useSchematicEvents,
|
|
2430
3068
|
useSchematicFlag,
|