@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
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
UsagePeriod: () => UsagePeriod,
|
|
38
38
|
useSchematic: () => useSchematic,
|
|
39
39
|
useSchematicContext: () => useSchematicContext,
|
|
40
|
+
useSchematicCreditBalance: () => useSchematicCreditBalance,
|
|
40
41
|
useSchematicEntitlement: () => useSchematicEntitlement,
|
|
41
42
|
useSchematicEvents: () => useSchematicEvents,
|
|
42
43
|
useSchematicFlag: () => useSchematicFlag,
|
|
@@ -53,7 +54,11 @@ var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
|
53
54
|
var __getProtoOf2 = Object.getPrototypeOf;
|
|
54
55
|
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
55
56
|
var __commonJS = (cb, mod) => function __require() {
|
|
56
|
-
|
|
57
|
+
try {
|
|
58
|
+
return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
59
|
+
} catch (e) {
|
|
60
|
+
throw mod = 0, e;
|
|
61
|
+
}
|
|
57
62
|
};
|
|
58
63
|
var __copyProps2 = (to, from, except, desc) => {
|
|
59
64
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -612,19 +617,16 @@ for (let i = 0; i < 256; ++i) {
|
|
|
612
617
|
function unsafeStringify(arr, offset = 0) {
|
|
613
618
|
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();
|
|
614
619
|
}
|
|
615
|
-
var getRandomValues;
|
|
616
620
|
var rnds8 = new Uint8Array(16);
|
|
617
621
|
function rng() {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
622
|
+
return crypto.getRandomValues(rnds8);
|
|
623
|
+
}
|
|
624
|
+
function v4(options, buf, offset) {
|
|
625
|
+
if (!buf && !options && crypto.randomUUID) {
|
|
626
|
+
return crypto.randomUUID();
|
|
623
627
|
}
|
|
624
|
-
return
|
|
628
|
+
return _v4(options, buf, offset);
|
|
625
629
|
}
|
|
626
|
-
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
627
|
-
var native_default = { randomUUID };
|
|
628
630
|
function _v4(options, buf, offset) {
|
|
629
631
|
options = options || {};
|
|
630
632
|
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
@@ -645,12 +647,6 @@ function _v4(options, buf, offset) {
|
|
|
645
647
|
}
|
|
646
648
|
return unsafeStringify(rnds);
|
|
647
649
|
}
|
|
648
|
-
function v4(options, buf, offset) {
|
|
649
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
650
|
-
return native_default.randomUUID();
|
|
651
|
-
}
|
|
652
|
-
return _v4(options, buf, offset);
|
|
653
|
-
}
|
|
654
650
|
var v4_default = v4;
|
|
655
651
|
var import_polyfill = __toESM2(require_browser_polyfill());
|
|
656
652
|
function EntitlementValueTypeFromJSON(json) {
|
|
@@ -659,6 +655,18 @@ function EntitlementValueTypeFromJSON(json) {
|
|
|
659
655
|
function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
660
656
|
return json;
|
|
661
657
|
}
|
|
658
|
+
function MetricPeriodMonthResetFromJSON(json) {
|
|
659
|
+
return MetricPeriodMonthResetFromJSONTyped(json, false);
|
|
660
|
+
}
|
|
661
|
+
function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
|
|
662
|
+
return json;
|
|
663
|
+
}
|
|
664
|
+
function MetricPeriodFromJSON(json) {
|
|
665
|
+
return MetricPeriodFromJSONTyped(json, false);
|
|
666
|
+
}
|
|
667
|
+
function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
|
|
668
|
+
return json;
|
|
669
|
+
}
|
|
662
670
|
function FeatureEntitlementFromJSON(json) {
|
|
663
671
|
return FeatureEntitlementFromJSONTyped(json, false);
|
|
664
672
|
}
|
|
@@ -668,21 +676,31 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
668
676
|
}
|
|
669
677
|
return {
|
|
670
678
|
allocation: json["allocation"] == null ? void 0 : json["allocation"],
|
|
679
|
+
consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
|
|
671
680
|
creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
|
|
672
681
|
creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
|
|
682
|
+
creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
|
|
683
|
+
creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
|
|
673
684
|
creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
|
|
674
685
|
creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
|
|
675
686
|
eventName: json["event_name"] == null ? void 0 : json["event_name"],
|
|
687
|
+
eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
|
|
676
688
|
featureId: json["feature_id"],
|
|
677
689
|
featureKey: json["feature_key"],
|
|
678
|
-
metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
|
|
690
|
+
metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
|
|
679
691
|
metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
|
|
680
|
-
monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
|
|
692
|
+
monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
|
|
681
693
|
softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
|
|
682
694
|
usage: json["usage"] == null ? void 0 : json["usage"],
|
|
683
695
|
valueType: EntitlementValueTypeFromJSON(json["value_type"])
|
|
684
696
|
};
|
|
685
697
|
}
|
|
698
|
+
function RuleTypeFromJSON(json) {
|
|
699
|
+
return RuleTypeFromJSONTyped(json, false);
|
|
700
|
+
}
|
|
701
|
+
function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
702
|
+
return json;
|
|
703
|
+
}
|
|
686
704
|
function CheckFlagResponseDataFromJSON(json) {
|
|
687
705
|
return CheckFlagResponseDataFromJSONTyped(json, false);
|
|
688
706
|
}
|
|
@@ -697,13 +715,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
697
715
|
featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
|
|
698
716
|
featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
|
|
699
717
|
featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
|
|
700
|
-
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
|
|
718
|
+
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
|
|
701
719
|
featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
|
|
702
720
|
flag: json["flag"],
|
|
703
721
|
flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
|
|
704
722
|
reason: json["reason"],
|
|
705
723
|
ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
|
|
706
|
-
ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
|
|
724
|
+
ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
|
|
707
725
|
userId: json["user_id"] == null ? void 0 : json["user_id"],
|
|
708
726
|
value: json["value"]
|
|
709
727
|
};
|
|
@@ -720,6 +738,268 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
720
738
|
params: json["params"]
|
|
721
739
|
};
|
|
722
740
|
}
|
|
741
|
+
var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
|
|
742
|
+
var Configuration = class {
|
|
743
|
+
constructor(configuration = {}) {
|
|
744
|
+
this.configuration = configuration;
|
|
745
|
+
}
|
|
746
|
+
configuration;
|
|
747
|
+
set config(configuration) {
|
|
748
|
+
this.configuration = configuration;
|
|
749
|
+
}
|
|
750
|
+
get basePath() {
|
|
751
|
+
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
|
752
|
+
}
|
|
753
|
+
get fetchApi() {
|
|
754
|
+
return this.configuration.fetchApi;
|
|
755
|
+
}
|
|
756
|
+
get middleware() {
|
|
757
|
+
return this.configuration.middleware || [];
|
|
758
|
+
}
|
|
759
|
+
get queryParamsStringify() {
|
|
760
|
+
return this.configuration.queryParamsStringify || querystring;
|
|
761
|
+
}
|
|
762
|
+
get username() {
|
|
763
|
+
return this.configuration.username;
|
|
764
|
+
}
|
|
765
|
+
get password() {
|
|
766
|
+
return this.configuration.password;
|
|
767
|
+
}
|
|
768
|
+
get apiKey() {
|
|
769
|
+
const apiKey = this.configuration.apiKey;
|
|
770
|
+
if (apiKey) {
|
|
771
|
+
return typeof apiKey === "function" ? apiKey : () => apiKey;
|
|
772
|
+
}
|
|
773
|
+
return void 0;
|
|
774
|
+
}
|
|
775
|
+
get accessToken() {
|
|
776
|
+
const accessToken = this.configuration.accessToken;
|
|
777
|
+
if (accessToken) {
|
|
778
|
+
return typeof accessToken === "function" ? accessToken : async () => accessToken;
|
|
779
|
+
}
|
|
780
|
+
return void 0;
|
|
781
|
+
}
|
|
782
|
+
get headers() {
|
|
783
|
+
return this.configuration.headers;
|
|
784
|
+
}
|
|
785
|
+
get credentials() {
|
|
786
|
+
return this.configuration.credentials;
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
var DefaultConfig = new Configuration();
|
|
790
|
+
var BaseAPI = class _BaseAPI {
|
|
791
|
+
constructor(configuration = DefaultConfig) {
|
|
792
|
+
this.configuration = configuration;
|
|
793
|
+
this.middleware = configuration.middleware;
|
|
794
|
+
}
|
|
795
|
+
configuration;
|
|
796
|
+
static jsonRegex = new RegExp(
|
|
797
|
+
"^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
|
|
798
|
+
"i"
|
|
799
|
+
);
|
|
800
|
+
middleware;
|
|
801
|
+
withMiddleware(...middlewares) {
|
|
802
|
+
const next = this.clone();
|
|
803
|
+
next.middleware = next.middleware.concat(...middlewares);
|
|
804
|
+
return next;
|
|
805
|
+
}
|
|
806
|
+
withPreMiddleware(...preMiddlewares) {
|
|
807
|
+
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
|
808
|
+
return this.withMiddleware(...middlewares);
|
|
809
|
+
}
|
|
810
|
+
withPostMiddleware(...postMiddlewares) {
|
|
811
|
+
const middlewares = postMiddlewares.map((post) => ({ post }));
|
|
812
|
+
return this.withMiddleware(...middlewares);
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Check if the given MIME is a JSON MIME.
|
|
816
|
+
* JSON MIME examples:
|
|
817
|
+
* application/json
|
|
818
|
+
* application/json; charset=UTF8
|
|
819
|
+
* APPLICATION/JSON
|
|
820
|
+
* application/vnd.company+json
|
|
821
|
+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
|
822
|
+
* @return True if the given MIME is JSON, false otherwise.
|
|
823
|
+
*/
|
|
824
|
+
isJsonMime(mime) {
|
|
825
|
+
if (!mime) {
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
return _BaseAPI.jsonRegex.test(mime);
|
|
829
|
+
}
|
|
830
|
+
async request(context, initOverrides) {
|
|
831
|
+
const { url, init } = await this.createFetchParams(context, initOverrides);
|
|
832
|
+
const response = await this.fetchApi(url, init);
|
|
833
|
+
if (response && response.status >= 200 && response.status < 300) {
|
|
834
|
+
return response;
|
|
835
|
+
}
|
|
836
|
+
throw new ResponseError(response, "Response returned an error code");
|
|
837
|
+
}
|
|
838
|
+
async createFetchParams(context, initOverrides) {
|
|
839
|
+
let url = this.configuration.basePath + context.path;
|
|
840
|
+
if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
|
|
841
|
+
url += "?" + this.configuration.queryParamsStringify(context.query);
|
|
842
|
+
}
|
|
843
|
+
const headers = Object.assign(
|
|
844
|
+
{},
|
|
845
|
+
this.configuration.headers,
|
|
846
|
+
context.headers
|
|
847
|
+
);
|
|
848
|
+
Object.keys(headers).forEach(
|
|
849
|
+
(key) => headers[key] === void 0 ? delete headers[key] : {}
|
|
850
|
+
);
|
|
851
|
+
const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
|
|
852
|
+
const initParams = {
|
|
853
|
+
method: context.method,
|
|
854
|
+
headers,
|
|
855
|
+
body: context.body,
|
|
856
|
+
credentials: this.configuration.credentials
|
|
857
|
+
};
|
|
858
|
+
const overriddenInit = {
|
|
859
|
+
...initParams,
|
|
860
|
+
...await initOverrideFn({
|
|
861
|
+
init: initParams,
|
|
862
|
+
context
|
|
863
|
+
})
|
|
864
|
+
};
|
|
865
|
+
let body;
|
|
866
|
+
if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
|
|
867
|
+
body = overriddenInit.body;
|
|
868
|
+
} else if (this.isJsonMime(headers["Content-Type"])) {
|
|
869
|
+
body = JSON.stringify(overriddenInit.body);
|
|
870
|
+
} else {
|
|
871
|
+
body = overriddenInit.body;
|
|
872
|
+
}
|
|
873
|
+
const init = {
|
|
874
|
+
...overriddenInit,
|
|
875
|
+
body
|
|
876
|
+
};
|
|
877
|
+
return { url, init };
|
|
878
|
+
}
|
|
879
|
+
fetchApi = async (url, init) => {
|
|
880
|
+
let fetchParams = { url, init };
|
|
881
|
+
for (const middleware of this.middleware) {
|
|
882
|
+
if (middleware.pre) {
|
|
883
|
+
fetchParams = await middleware.pre({
|
|
884
|
+
fetch: this.fetchApi,
|
|
885
|
+
...fetchParams
|
|
886
|
+
}) || fetchParams;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
let response = void 0;
|
|
890
|
+
try {
|
|
891
|
+
response = await (this.configuration.fetchApi || fetch)(
|
|
892
|
+
fetchParams.url,
|
|
893
|
+
fetchParams.init
|
|
894
|
+
);
|
|
895
|
+
} catch (e) {
|
|
896
|
+
for (const middleware of this.middleware) {
|
|
897
|
+
if (middleware.onError) {
|
|
898
|
+
response = await middleware.onError({
|
|
899
|
+
fetch: this.fetchApi,
|
|
900
|
+
url: fetchParams.url,
|
|
901
|
+
init: fetchParams.init,
|
|
902
|
+
error: e,
|
|
903
|
+
response: response ? response.clone() : void 0
|
|
904
|
+
}) || response;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
if (response === void 0) {
|
|
908
|
+
if (e instanceof Error) {
|
|
909
|
+
throw new FetchError(
|
|
910
|
+
e,
|
|
911
|
+
"The request failed and the interceptors did not return an alternative response"
|
|
912
|
+
);
|
|
913
|
+
} else {
|
|
914
|
+
throw e;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
for (const middleware of this.middleware) {
|
|
919
|
+
if (middleware.post) {
|
|
920
|
+
response = await middleware.post({
|
|
921
|
+
fetch: this.fetchApi,
|
|
922
|
+
url: fetchParams.url,
|
|
923
|
+
init: fetchParams.init,
|
|
924
|
+
response: response.clone()
|
|
925
|
+
}) || response;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return response;
|
|
929
|
+
};
|
|
930
|
+
/**
|
|
931
|
+
* Create a shallow clone of `this` by constructing a new instance
|
|
932
|
+
* and then shallow cloning data members.
|
|
933
|
+
*/
|
|
934
|
+
clone() {
|
|
935
|
+
const constructor = this.constructor;
|
|
936
|
+
const next = new constructor(this.configuration);
|
|
937
|
+
next.middleware = this.middleware.slice();
|
|
938
|
+
return next;
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
function isBlob(value) {
|
|
942
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
943
|
+
}
|
|
944
|
+
function isFormData(value) {
|
|
945
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
946
|
+
}
|
|
947
|
+
var ResponseError = class extends Error {
|
|
948
|
+
constructor(response, msg) {
|
|
949
|
+
super(msg);
|
|
950
|
+
this.response = response;
|
|
951
|
+
}
|
|
952
|
+
response;
|
|
953
|
+
name = "ResponseError";
|
|
954
|
+
};
|
|
955
|
+
var FetchError = class extends Error {
|
|
956
|
+
constructor(cause, msg) {
|
|
957
|
+
super(msg);
|
|
958
|
+
this.cause = cause;
|
|
959
|
+
}
|
|
960
|
+
cause;
|
|
961
|
+
name = "FetchError";
|
|
962
|
+
};
|
|
963
|
+
function querystring(params, prefix = "") {
|
|
964
|
+
return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
|
|
965
|
+
}
|
|
966
|
+
function querystringSingleKey(key, value, keyPrefix = "") {
|
|
967
|
+
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
|
968
|
+
if (value instanceof Array) {
|
|
969
|
+
const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
|
|
970
|
+
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
|
971
|
+
}
|
|
972
|
+
if (value instanceof Set) {
|
|
973
|
+
const valueAsArray = Array.from(value);
|
|
974
|
+
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
|
975
|
+
}
|
|
976
|
+
if (value instanceof Date) {
|
|
977
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
|
978
|
+
}
|
|
979
|
+
if (value instanceof Object) {
|
|
980
|
+
return querystring(value, fullKey);
|
|
981
|
+
}
|
|
982
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
|
983
|
+
}
|
|
984
|
+
function mapValues(data, fn) {
|
|
985
|
+
return Object.keys(data).reduce(
|
|
986
|
+
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
|
987
|
+
{}
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
function CompanyCreditBalanceFromJSON(json) {
|
|
991
|
+
return CompanyCreditBalanceFromJSONTyped(json, false);
|
|
992
|
+
}
|
|
993
|
+
function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
|
|
994
|
+
if (json == null) {
|
|
995
|
+
return json;
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
remaining: json["remaining"],
|
|
999
|
+
reserved: json["reserved"],
|
|
1000
|
+
settled: json["settled"]
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
723
1003
|
var TrialStatus = {
|
|
724
1004
|
Active: "active",
|
|
725
1005
|
Converted: "converted",
|
|
@@ -753,6 +1033,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
753
1033
|
return json;
|
|
754
1034
|
}
|
|
755
1035
|
return {
|
|
1036
|
+
creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
|
|
756
1037
|
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
757
1038
|
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
758
1039
|
};
|
|
@@ -835,7 +1116,10 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
835
1116
|
return {
|
|
836
1117
|
featureUsageExceeded,
|
|
837
1118
|
companyId: companyId == null ? void 0 : companyId,
|
|
1119
|
+
creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
|
|
838
1120
|
creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
|
|
1121
|
+
creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
|
|
1122
|
+
creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
|
|
839
1123
|
error: error == null ? void 0 : error,
|
|
840
1124
|
featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
|
|
841
1125
|
featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
|
|
@@ -861,6 +1145,22 @@ var CheckPlanReturnFromJSON = (json) => {
|
|
|
861
1145
|
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
862
1146
|
};
|
|
863
1147
|
};
|
|
1148
|
+
var CreditBalancesFromJSON = (json) => {
|
|
1149
|
+
if (json == null || typeof json !== "object") {
|
|
1150
|
+
return {};
|
|
1151
|
+
}
|
|
1152
|
+
const balances = {};
|
|
1153
|
+
for (const [creditId, raw] of Object.entries(json)) {
|
|
1154
|
+
if (raw == null || typeof raw !== "object") continue;
|
|
1155
|
+
const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
|
|
1156
|
+
if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
|
|
1157
|
+
continue;
|
|
1158
|
+
}
|
|
1159
|
+
balances[creditId] = { remaining, reserved, settled };
|
|
1160
|
+
}
|
|
1161
|
+
return balances;
|
|
1162
|
+
};
|
|
1163
|
+
var cacheVersion = "bb56e75d";
|
|
864
1164
|
function contextString(context) {
|
|
865
1165
|
const sortedContext = Object.keys(context).reduce((acc, key) => {
|
|
866
1166
|
const sortedKeys = Object.keys(
|
|
@@ -875,8 +1175,12 @@ function contextString(context) {
|
|
|
875
1175
|
}, {});
|
|
876
1176
|
return JSON.stringify(sortedContext);
|
|
877
1177
|
}
|
|
878
|
-
var version = "1.
|
|
1178
|
+
var version = "1.5.0";
|
|
879
1179
|
var anonymousIdKey = "schematicId";
|
|
1180
|
+
var flagStateCachePrefix = "schematicCache";
|
|
1181
|
+
var flagStateCacheMaxContexts = 10;
|
|
1182
|
+
var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1183
|
+
var emptyCreditBalances = Object.freeze({});
|
|
880
1184
|
var Schematic = class {
|
|
881
1185
|
additionalHeaders = {};
|
|
882
1186
|
apiKey;
|
|
@@ -893,11 +1197,17 @@ var Schematic = class {
|
|
|
893
1197
|
isPending = true;
|
|
894
1198
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
895
1199
|
planListeners = /* @__PURE__ */ new Set();
|
|
1200
|
+
creditBalanceListeners = /* @__PURE__ */ new Set();
|
|
896
1201
|
storage;
|
|
1202
|
+
persistFlagState = true;
|
|
1203
|
+
flagStateCacheKey;
|
|
1204
|
+
flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
|
|
1205
|
+
cachedFlagState = null;
|
|
897
1206
|
useWebSocket = false;
|
|
898
1207
|
checks = {};
|
|
899
1208
|
featureUsageEventMap = {};
|
|
900
1209
|
planChecks = {};
|
|
1210
|
+
creditBalances = {};
|
|
901
1211
|
webSocketUrl = "wss://api.schematichq.com";
|
|
902
1212
|
webSocketConnectionTimeout = 1e4;
|
|
903
1213
|
webSocketReconnect = true;
|
|
@@ -926,11 +1236,16 @@ var Schematic = class {
|
|
|
926
1236
|
fallbackCheckCache = {};
|
|
927
1237
|
constructor(apiKey, options) {
|
|
928
1238
|
this.apiKey = apiKey;
|
|
1239
|
+
this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
|
|
929
1240
|
this.eventQueue = [];
|
|
930
1241
|
this.contextDependentEventQueue = [];
|
|
931
1242
|
this.useWebSocket = options?.useWebSocket ?? false;
|
|
932
1243
|
this.debugEnabled = options?.debug ?? false;
|
|
933
1244
|
this.offlineEnabled = options?.offline ?? false;
|
|
1245
|
+
this.persistFlagState = options?.persistFlagState ?? true;
|
|
1246
|
+
if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
|
|
1247
|
+
this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
|
|
1248
|
+
}
|
|
934
1249
|
if (typeof window !== "undefined" && typeof window.location !== "undefined") {
|
|
935
1250
|
const params = new URLSearchParams(window.location.search);
|
|
936
1251
|
const debugParam = params.get("schematic_debug");
|
|
@@ -963,6 +1278,7 @@ var Schematic = class {
|
|
|
963
1278
|
} catch {
|
|
964
1279
|
}
|
|
965
1280
|
}
|
|
1281
|
+
this.hydrateFlagStateFromCache();
|
|
966
1282
|
if (options?.apiUrl !== void 0) {
|
|
967
1283
|
this.apiUrl = options.apiUrl;
|
|
968
1284
|
}
|
|
@@ -1256,6 +1572,29 @@ var Schematic = class {
|
|
|
1256
1572
|
});
|
|
1257
1573
|
this.notifyPlanListeners(plan);
|
|
1258
1574
|
}
|
|
1575
|
+
if (message.credit_balances !== void 0 && message.credit_balances !== null) {
|
|
1576
|
+
const contextStr = contextString(context);
|
|
1577
|
+
const updates = CreditBalancesFromJSON(message.credit_balances);
|
|
1578
|
+
const previous = this.creditBalances[contextStr] ?? {};
|
|
1579
|
+
let changed = false;
|
|
1580
|
+
const merged = { ...previous };
|
|
1581
|
+
for (const [creditId, next] of Object.entries(updates)) {
|
|
1582
|
+
const current = previous[creditId];
|
|
1583
|
+
if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
|
|
1584
|
+
merged[creditId] = next;
|
|
1585
|
+
changed = true;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
if (changed) {
|
|
1589
|
+
this.creditBalances[contextStr] = merged;
|
|
1590
|
+
this.debug(
|
|
1591
|
+
`WebSocket credit balance update received. Notifying listeners`,
|
|
1592
|
+
{ creditBalances: merged }
|
|
1593
|
+
);
|
|
1594
|
+
this.notifyCreditBalanceListeners(merged);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
this.persistContextToCache(contextString(context));
|
|
1259
1598
|
this.flushContextDependentEventQueue();
|
|
1260
1599
|
this.setIsPending(false);
|
|
1261
1600
|
};
|
|
@@ -1363,7 +1702,32 @@ var Schematic = class {
|
|
|
1363
1702
|
return;
|
|
1364
1703
|
}
|
|
1365
1704
|
try {
|
|
1366
|
-
|
|
1705
|
+
const newContextStr = contextString(context);
|
|
1706
|
+
const cacheHit = this.hasCachedValuesForContext(newContextStr);
|
|
1707
|
+
if (cacheHit) {
|
|
1708
|
+
this.debug(
|
|
1709
|
+
`setContext: cache hit for context, pre-resolving from cached values`
|
|
1710
|
+
);
|
|
1711
|
+
this.context = context;
|
|
1712
|
+
this.flushContextDependentEventQueue();
|
|
1713
|
+
this.setIsPending(false);
|
|
1714
|
+
const cachedChecks = this.checks[newContextStr] ?? {};
|
|
1715
|
+
for (const [flagKey, check] of Object.entries(cachedChecks)) {
|
|
1716
|
+
if (check === void 0) continue;
|
|
1717
|
+
this.notifyFlagCheckListeners(flagKey, check);
|
|
1718
|
+
this.notifyFlagValueListeners(flagKey, check.value);
|
|
1719
|
+
}
|
|
1720
|
+
const cachedPlan = this.planChecks[newContextStr];
|
|
1721
|
+
if (cachedPlan !== void 0) {
|
|
1722
|
+
this.notifyPlanListeners(cachedPlan);
|
|
1723
|
+
}
|
|
1724
|
+
const cachedCreditBalances = this.creditBalances[newContextStr];
|
|
1725
|
+
if (cachedCreditBalances !== void 0) {
|
|
1726
|
+
this.notifyCreditBalanceListeners(cachedCreditBalances);
|
|
1727
|
+
}
|
|
1728
|
+
} else {
|
|
1729
|
+
this.setIsPending(true);
|
|
1730
|
+
}
|
|
1367
1731
|
if (!this.conn) {
|
|
1368
1732
|
if (this.isConnecting) {
|
|
1369
1733
|
this.debug(
|
|
@@ -1374,7 +1738,7 @@ var Schematic = class {
|
|
|
1374
1738
|
}
|
|
1375
1739
|
if (this.conn !== null) {
|
|
1376
1740
|
const socket2 = await this.conn;
|
|
1377
|
-
await this.wsSendMessage(socket2, context);
|
|
1741
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1378
1742
|
return;
|
|
1379
1743
|
}
|
|
1380
1744
|
}
|
|
@@ -1390,7 +1754,7 @@ var Schematic = class {
|
|
|
1390
1754
|
this.conn = this.wsConnect();
|
|
1391
1755
|
const socket2 = await this.conn;
|
|
1392
1756
|
this.isConnecting = false;
|
|
1393
|
-
await this.wsSendMessage(socket2, context);
|
|
1757
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1394
1758
|
return;
|
|
1395
1759
|
} catch (error) {
|
|
1396
1760
|
this.isConnecting = false;
|
|
@@ -1398,7 +1762,7 @@ var Schematic = class {
|
|
|
1398
1762
|
}
|
|
1399
1763
|
}
|
|
1400
1764
|
const socket = await this.conn;
|
|
1401
|
-
await this.wsSendMessage(socket, context);
|
|
1765
|
+
await this.wsSendMessage(socket, context, cacheHit);
|
|
1402
1766
|
} catch (error) {
|
|
1403
1767
|
console.warn("Failed to establish WebSocket connection:", error);
|
|
1404
1768
|
this.context = context;
|
|
@@ -1458,10 +1822,12 @@ var Schematic = class {
|
|
|
1458
1822
|
`Optimistically updating feature usage for event: ${eventName}`,
|
|
1459
1823
|
{ quantity }
|
|
1460
1824
|
);
|
|
1825
|
+
let dirty = false;
|
|
1461
1826
|
Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
|
|
1462
1827
|
if (check === void 0) return;
|
|
1463
1828
|
const updatedCheck = { ...check };
|
|
1464
1829
|
if (typeof updatedCheck.featureUsage === "number") {
|
|
1830
|
+
dirty = true;
|
|
1465
1831
|
updatedCheck.featureUsage += quantity;
|
|
1466
1832
|
if (typeof updatedCheck.featureAllocation === "number") {
|
|
1467
1833
|
const wasExceeded = updatedCheck.featureUsageExceeded === true;
|
|
@@ -1491,6 +1857,9 @@ var Schematic = class {
|
|
|
1491
1857
|
this.notifyFlagValueListeners(flagKey, updatedCheck.value);
|
|
1492
1858
|
}
|
|
1493
1859
|
});
|
|
1860
|
+
if (dirty) {
|
|
1861
|
+
this.persistContextToCache(contextString(this.context));
|
|
1862
|
+
}
|
|
1494
1863
|
};
|
|
1495
1864
|
/**
|
|
1496
1865
|
* Event processing
|
|
@@ -1593,6 +1962,206 @@ var Schematic = class {
|
|
|
1593
1962
|
this.storage.setItem(anonymousIdKey, generatedAnonymousId);
|
|
1594
1963
|
return generatedAnonymousId;
|
|
1595
1964
|
};
|
|
1965
|
+
hasCachedValuesForContext = (contextStr) => {
|
|
1966
|
+
const cachedChecks = this.checks[contextStr];
|
|
1967
|
+
if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
|
|
1968
|
+
return true;
|
|
1969
|
+
}
|
|
1970
|
+
if (this.planChecks[contextStr] !== void 0) {
|
|
1971
|
+
return true;
|
|
1972
|
+
}
|
|
1973
|
+
const cachedCreditBalances = this.creditBalances[contextStr];
|
|
1974
|
+
return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
|
|
1975
|
+
};
|
|
1976
|
+
readFlagStateCache = () => {
|
|
1977
|
+
if (!this.persistFlagState || this.storage === void 0) {
|
|
1978
|
+
return null;
|
|
1979
|
+
}
|
|
1980
|
+
let raw;
|
|
1981
|
+
try {
|
|
1982
|
+
raw = this.storage.getItem(this.flagStateCacheKey);
|
|
1983
|
+
} catch (error) {
|
|
1984
|
+
this.debug("Failed to read flag state cache:", error);
|
|
1985
|
+
return null;
|
|
1986
|
+
}
|
|
1987
|
+
if (raw === null || raw === void 0) {
|
|
1988
|
+
return null;
|
|
1989
|
+
}
|
|
1990
|
+
let parsed;
|
|
1991
|
+
try {
|
|
1992
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1993
|
+
} catch (error) {
|
|
1994
|
+
this.debug("Flag state cache is not valid JSON, ignoring:", error);
|
|
1995
|
+
return null;
|
|
1996
|
+
}
|
|
1997
|
+
if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
|
|
1998
|
+
this.debug(
|
|
1999
|
+
`Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
|
|
2000
|
+
{
|
|
2001
|
+
parsedType: typeof parsed,
|
|
2002
|
+
version: parsed?.version
|
|
2003
|
+
}
|
|
2004
|
+
);
|
|
2005
|
+
return null;
|
|
2006
|
+
}
|
|
2007
|
+
return parsed;
|
|
2008
|
+
};
|
|
2009
|
+
reviveCachedCheck = (raw) => {
|
|
2010
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2011
|
+
const obj = raw;
|
|
2012
|
+
if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
|
|
2013
|
+
return null;
|
|
2014
|
+
}
|
|
2015
|
+
const revived = { ...obj };
|
|
2016
|
+
if (typeof revived.featureUsageResetAt === "string") {
|
|
2017
|
+
const d = new Date(revived.featureUsageResetAt);
|
|
2018
|
+
revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
|
|
2019
|
+
}
|
|
2020
|
+
return revived;
|
|
2021
|
+
};
|
|
2022
|
+
reviveCachedPlan = (raw) => {
|
|
2023
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2024
|
+
const obj = raw;
|
|
2025
|
+
if (typeof obj.id !== "string" || typeof obj.name !== "string") {
|
|
2026
|
+
return null;
|
|
2027
|
+
}
|
|
2028
|
+
const revived = { ...obj };
|
|
2029
|
+
if (typeof revived.trialEndDate === "string") {
|
|
2030
|
+
const d = new Date(revived.trialEndDate);
|
|
2031
|
+
revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
|
|
2032
|
+
}
|
|
2033
|
+
return revived;
|
|
2034
|
+
};
|
|
2035
|
+
reviveCachedCreditBalances = (raw) => {
|
|
2036
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2037
|
+
const revived = {};
|
|
2038
|
+
for (const [creditId, value] of Object.entries(
|
|
2039
|
+
raw
|
|
2040
|
+
)) {
|
|
2041
|
+
if (value === null || typeof value !== "object") continue;
|
|
2042
|
+
const obj = value;
|
|
2043
|
+
if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
|
|
2044
|
+
continue;
|
|
2045
|
+
}
|
|
2046
|
+
revived[creditId] = {
|
|
2047
|
+
remaining: obj.remaining,
|
|
2048
|
+
reserved: obj.reserved,
|
|
2049
|
+
settled: obj.settled
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
return Object.keys(revived).length > 0 ? revived : null;
|
|
2053
|
+
};
|
|
2054
|
+
hydrateFlagStateFromCache = () => {
|
|
2055
|
+
const parsed = this.readFlagStateCache();
|
|
2056
|
+
if (parsed === null) return;
|
|
2057
|
+
const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
|
|
2058
|
+
const fresh = {};
|
|
2059
|
+
let contextsLoaded = 0;
|
|
2060
|
+
let contextsExpired = 0;
|
|
2061
|
+
for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
|
|
2062
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2063
|
+
if (typeof entry.updatedAt !== "number") continue;
|
|
2064
|
+
if (entry.updatedAt < cutoff) {
|
|
2065
|
+
contextsExpired += 1;
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
const revivedChecks = {};
|
|
2069
|
+
if (entry.checks !== null && typeof entry.checks === "object") {
|
|
2070
|
+
for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
|
|
2071
|
+
const revived = this.reviveCachedCheck(rawCheck);
|
|
2072
|
+
if (revived === null || revived.flag !== flagKey) continue;
|
|
2073
|
+
revivedChecks[flagKey] = revived;
|
|
2074
|
+
if (typeof revived.featureUsageEvent === "string") {
|
|
2075
|
+
this.updateFeatureUsageEventMap(revived);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
if (Object.keys(revivedChecks).length > 0) {
|
|
2079
|
+
this.checks[contextStr] = revivedChecks;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
let revivedPlan;
|
|
2083
|
+
if (entry.plan !== void 0 && entry.plan !== null) {
|
|
2084
|
+
const p = this.reviveCachedPlan(entry.plan);
|
|
2085
|
+
if (p !== null) {
|
|
2086
|
+
revivedPlan = p;
|
|
2087
|
+
this.planChecks[contextStr] = p;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
let revivedCreditBalances;
|
|
2091
|
+
if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
|
|
2092
|
+
const balances = this.reviveCachedCreditBalances(entry.creditBalances);
|
|
2093
|
+
if (balances !== null) {
|
|
2094
|
+
revivedCreditBalances = balances;
|
|
2095
|
+
this.creditBalances[contextStr] = balances;
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
fresh[contextStr] = {
|
|
2099
|
+
checks: revivedChecks,
|
|
2100
|
+
plan: revivedPlan,
|
|
2101
|
+
creditBalances: revivedCreditBalances,
|
|
2102
|
+
updatedAt: entry.updatedAt
|
|
2103
|
+
};
|
|
2104
|
+
contextsLoaded += 1;
|
|
2105
|
+
}
|
|
2106
|
+
this.cachedFlagState = { version: cacheVersion, contexts: fresh };
|
|
2107
|
+
this.debug(
|
|
2108
|
+
`Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
|
|
2109
|
+
);
|
|
2110
|
+
};
|
|
2111
|
+
persistContextToCache = (contextStr) => {
|
|
2112
|
+
const checksForContext = this.checks[contextStr];
|
|
2113
|
+
const planForContext = this.planChecks[contextStr];
|
|
2114
|
+
const creditBalancesForContext = this.creditBalances[contextStr];
|
|
2115
|
+
if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
if (this.cachedFlagState === null) {
|
|
2119
|
+
this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
|
|
2120
|
+
version: cacheVersion,
|
|
2121
|
+
contexts: {}
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
const cleanChecks = {};
|
|
2125
|
+
if (checksForContext !== void 0) {
|
|
2126
|
+
for (const [flagKey, check] of Object.entries(checksForContext)) {
|
|
2127
|
+
if (check !== void 0) cleanChecks[flagKey] = check;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
this.cachedFlagState.contexts[contextStr] = {
|
|
2131
|
+
checks: cleanChecks,
|
|
2132
|
+
plan: planForContext,
|
|
2133
|
+
creditBalances: creditBalancesForContext,
|
|
2134
|
+
updatedAt: Date.now()
|
|
2135
|
+
};
|
|
2136
|
+
const entries = Object.entries(this.cachedFlagState.contexts);
|
|
2137
|
+
if (entries.length > flagStateCacheMaxContexts) {
|
|
2138
|
+
entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
|
2139
|
+
const survivors = entries.slice(0, flagStateCacheMaxContexts);
|
|
2140
|
+
const survivorKeys = new Set(survivors.map(([k]) => k));
|
|
2141
|
+
for (const key of Object.keys(this.checks)) {
|
|
2142
|
+
if (!survivorKeys.has(key)) delete this.checks[key];
|
|
2143
|
+
}
|
|
2144
|
+
for (const key of Object.keys(this.planChecks)) {
|
|
2145
|
+
if (!survivorKeys.has(key)) delete this.planChecks[key];
|
|
2146
|
+
}
|
|
2147
|
+
for (const key of Object.keys(this.creditBalances)) {
|
|
2148
|
+
if (!survivorKeys.has(key)) delete this.creditBalances[key];
|
|
2149
|
+
}
|
|
2150
|
+
this.cachedFlagState = {
|
|
2151
|
+
version: cacheVersion,
|
|
2152
|
+
contexts: Object.fromEntries(survivors)
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
if (!this.persistFlagState || this.storage === void 0) return;
|
|
2156
|
+
try {
|
|
2157
|
+
this.storage.setItem(
|
|
2158
|
+
this.flagStateCacheKey,
|
|
2159
|
+
JSON.stringify(this.cachedFlagState)
|
|
2160
|
+
);
|
|
2161
|
+
} catch (error) {
|
|
2162
|
+
this.debug("Failed to write flag state cache:", error);
|
|
2163
|
+
}
|
|
2164
|
+
};
|
|
1596
2165
|
handleEvent = (eventType, eventBody) => {
|
|
1597
2166
|
const event = {
|
|
1598
2167
|
api_key: this.apiKey,
|
|
@@ -1853,6 +2422,9 @@ var Schematic = class {
|
|
|
1853
2422
|
if (this.conn !== null) {
|
|
1854
2423
|
try {
|
|
1855
2424
|
const socket = await this.conn;
|
|
2425
|
+
if (this.currentWebSocket === socket) {
|
|
2426
|
+
this.currentWebSocket = null;
|
|
2427
|
+
}
|
|
1856
2428
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
1857
2429
|
socket.close();
|
|
1858
2430
|
}
|
|
@@ -2018,6 +2590,7 @@ var Schematic = class {
|
|
|
2018
2590
|
this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
|
|
2019
2591
|
let timeoutId = null;
|
|
2020
2592
|
let isResolved = false;
|
|
2593
|
+
let didOpen = false;
|
|
2021
2594
|
timeoutId = setTimeout(() => {
|
|
2022
2595
|
if (!isResolved) {
|
|
2023
2596
|
isResolved = true;
|
|
@@ -2031,6 +2604,7 @@ var Schematic = class {
|
|
|
2031
2604
|
webSocket.onopen = () => {
|
|
2032
2605
|
if (isResolved) return;
|
|
2033
2606
|
isResolved = true;
|
|
2607
|
+
didOpen = true;
|
|
2034
2608
|
if (timeoutId !== null) {
|
|
2035
2609
|
clearTimeout(timeoutId);
|
|
2036
2610
|
}
|
|
@@ -2056,11 +2630,12 @@ var Schematic = class {
|
|
|
2056
2630
|
}
|
|
2057
2631
|
this.debug(`WebSocket connection ${connectionId} closed`);
|
|
2058
2632
|
this.conn = null;
|
|
2633
|
+
const wasCurrent = this.currentWebSocket === webSocket;
|
|
2059
2634
|
if (this.currentWebSocket === webSocket) {
|
|
2060
2635
|
this.currentWebSocket = null;
|
|
2061
2636
|
this.isConnecting = false;
|
|
2062
2637
|
}
|
|
2063
|
-
if (
|
|
2638
|
+
if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
|
|
2064
2639
|
this.attemptReconnect();
|
|
2065
2640
|
}
|
|
2066
2641
|
};
|
|
@@ -2156,6 +2731,16 @@ var Schematic = class {
|
|
|
2156
2731
|
const plan = this.planChecks[contextStr];
|
|
2157
2732
|
return plan;
|
|
2158
2733
|
};
|
|
2734
|
+
/** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
|
|
2735
|
+
getCreditBalances = () => {
|
|
2736
|
+
const contextStr = contextString(this.context);
|
|
2737
|
+
return this.creditBalances[contextStr] ?? emptyCreditBalances;
|
|
2738
|
+
};
|
|
2739
|
+
/** Get the company's lease-aware balance for a single credit type in the current context */
|
|
2740
|
+
getCreditBalance = (creditId) => {
|
|
2741
|
+
const contextStr = contextString(this.context);
|
|
2742
|
+
return this.creditBalances[contextStr]?.[creditId];
|
|
2743
|
+
};
|
|
2159
2744
|
// flag checks state
|
|
2160
2745
|
getFlagCheck = (flagKey) => {
|
|
2161
2746
|
const contextStr = contextString(this.context);
|
|
@@ -2215,6 +2800,13 @@ var Schematic = class {
|
|
|
2215
2800
|
this.planListeners.delete(listener);
|
|
2216
2801
|
};
|
|
2217
2802
|
};
|
|
2803
|
+
/** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
|
|
2804
|
+
addCreditBalanceListener = (listener) => {
|
|
2805
|
+
this.creditBalanceListeners.add(listener);
|
|
2806
|
+
return () => {
|
|
2807
|
+
this.creditBalanceListeners.delete(listener);
|
|
2808
|
+
};
|
|
2809
|
+
};
|
|
2218
2810
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2219
2811
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2220
2812
|
if (listeners.size > 0) {
|
|
@@ -2278,6 +2870,17 @@ var Schematic = class {
|
|
|
2278
2870
|
});
|
|
2279
2871
|
});
|
|
2280
2872
|
};
|
|
2873
|
+
notifyCreditBalanceListeners = (value) => {
|
|
2874
|
+
const listeners = this.creditBalanceListeners ?? [];
|
|
2875
|
+
if (listeners.size > 0) {
|
|
2876
|
+
this.debug(`Notifying ${listeners.size} credit balance listeners`, {
|
|
2877
|
+
value
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2880
|
+
listeners.forEach(
|
|
2881
|
+
(listener) => notifyCreditBalanceListener(listener, value)
|
|
2882
|
+
);
|
|
2883
|
+
};
|
|
2281
2884
|
};
|
|
2282
2885
|
var notifyPendingListener = (listener, value) => {
|
|
2283
2886
|
if (listener.length > 0) {
|
|
@@ -2307,12 +2910,19 @@ var notifyPlanListener = (listener, value) => {
|
|
|
2307
2910
|
listener();
|
|
2308
2911
|
}
|
|
2309
2912
|
};
|
|
2913
|
+
var notifyCreditBalanceListener = (listener, value) => {
|
|
2914
|
+
if (listener.length > 0) {
|
|
2915
|
+
listener(value);
|
|
2916
|
+
} else {
|
|
2917
|
+
listener();
|
|
2918
|
+
}
|
|
2919
|
+
};
|
|
2310
2920
|
|
|
2311
2921
|
// src/context/schematic.tsx
|
|
2312
2922
|
var import_react = __toESM(require("react"));
|
|
2313
2923
|
|
|
2314
2924
|
// src/version.ts
|
|
2315
|
-
var version2 = "1.
|
|
2925
|
+
var version2 = "1.5.0";
|
|
2316
2926
|
|
|
2317
2927
|
// src/context/schematic.tsx
|
|
2318
2928
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -2455,6 +3065,34 @@ var useSchematicPlan = (opts) => {
|
|
|
2455
3065
|
}, [client, fallbackPlan]);
|
|
2456
3066
|
return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackPlan);
|
|
2457
3067
|
};
|
|
3068
|
+
var useSchematicCreditBalance = (creditId, opts) => {
|
|
3069
|
+
const client = useSchematicClient(opts);
|
|
3070
|
+
const subscribe = (0, import_react2.useCallback)(
|
|
3071
|
+
(callback) => client.addCreditBalanceListener(callback),
|
|
3072
|
+
[client]
|
|
3073
|
+
);
|
|
3074
|
+
const getSnapshot = (0, import_react2.useCallback)(
|
|
3075
|
+
() => client.getCreditBalance(creditId),
|
|
3076
|
+
[client, creditId]
|
|
3077
|
+
);
|
|
3078
|
+
const balance = (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
|
|
3079
|
+
const isPendingSubscribe = (0, import_react2.useCallback)(
|
|
3080
|
+
(callback) => client.addIsPendingListener(callback),
|
|
3081
|
+
[client]
|
|
3082
|
+
);
|
|
3083
|
+
const isPending = (0, import_react2.useSyncExternalStore)(
|
|
3084
|
+
isPendingSubscribe,
|
|
3085
|
+
() => client.getIsPending(),
|
|
3086
|
+
() => true
|
|
3087
|
+
);
|
|
3088
|
+
return (0, import_react2.useMemo)(
|
|
3089
|
+
() => ({
|
|
3090
|
+
balance: balance?.settled ?? 0,
|
|
3091
|
+
isLoading: balance === void 0 && isPending
|
|
3092
|
+
}),
|
|
3093
|
+
[balance, isPending]
|
|
3094
|
+
);
|
|
3095
|
+
};
|
|
2458
3096
|
var useSchematicIsPending = (opts) => {
|
|
2459
3097
|
const client = useSchematicClient(opts);
|
|
2460
3098
|
const subscribe = (0, import_react2.useCallback)(
|