@schematichq/schematic-js 1.3.2 → 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 +17 -0
- package/dist/schematic.browser.js +2 -2
- package/dist/schematic.cjs.js +662 -34
- package/dist/schematic.d.ts +163 -21
- package/dist/schematic.esm.js +662 -34
- package/package.json +16 -17
package/dist/schematic.esm.js
CHANGED
|
@@ -5,7 +5,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
7
|
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
|
|
8
|
+
try {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
} catch (e) {
|
|
11
|
+
throw mod = 0, e;
|
|
12
|
+
}
|
|
9
13
|
};
|
|
10
14
|
var __copyProps = (to, from, except, desc) => {
|
|
11
15
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -570,23 +574,18 @@ function unsafeStringify(arr, offset = 0) {
|
|
|
570
574
|
}
|
|
571
575
|
|
|
572
576
|
// node_modules/uuid/dist/rng.js
|
|
573
|
-
var getRandomValues;
|
|
574
577
|
var rnds8 = new Uint8Array(16);
|
|
575
578
|
function rng() {
|
|
576
|
-
|
|
577
|
-
if (typeof crypto === "undefined" || !crypto.getRandomValues) {
|
|
578
|
-
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
579
|
-
}
|
|
580
|
-
getRandomValues = crypto.getRandomValues.bind(crypto);
|
|
581
|
-
}
|
|
582
|
-
return getRandomValues(rnds8);
|
|
579
|
+
return crypto.getRandomValues(rnds8);
|
|
583
580
|
}
|
|
584
581
|
|
|
585
|
-
// node_modules/uuid/dist/native.js
|
|
586
|
-
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
587
|
-
var native_default = { randomUUID };
|
|
588
|
-
|
|
589
582
|
// node_modules/uuid/dist/v4.js
|
|
583
|
+
function v4(options, buf, offset) {
|
|
584
|
+
if (!buf && !options && crypto.randomUUID) {
|
|
585
|
+
return crypto.randomUUID();
|
|
586
|
+
}
|
|
587
|
+
return _v4(options, buf, offset);
|
|
588
|
+
}
|
|
590
589
|
function _v4(options, buf, offset) {
|
|
591
590
|
options = options || {};
|
|
592
591
|
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
@@ -607,12 +606,6 @@ function _v4(options, buf, offset) {
|
|
|
607
606
|
}
|
|
608
607
|
return unsafeStringify(rnds);
|
|
609
608
|
}
|
|
610
|
-
function v4(options, buf, offset) {
|
|
611
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
612
|
-
return native_default.randomUUID();
|
|
613
|
-
}
|
|
614
|
-
return _v4(options, buf, offset);
|
|
615
|
-
}
|
|
616
609
|
var v4_default = v4;
|
|
617
610
|
|
|
618
611
|
// src/index.ts
|
|
@@ -626,6 +619,22 @@ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
626
619
|
return json;
|
|
627
620
|
}
|
|
628
621
|
|
|
622
|
+
// src/types/api/models/MetricPeriodMonthReset.ts
|
|
623
|
+
function MetricPeriodMonthResetFromJSON(json) {
|
|
624
|
+
return MetricPeriodMonthResetFromJSONTyped(json, false);
|
|
625
|
+
}
|
|
626
|
+
function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
|
|
627
|
+
return json;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/types/api/models/MetricPeriod.ts
|
|
631
|
+
function MetricPeriodFromJSON(json) {
|
|
632
|
+
return MetricPeriodFromJSONTyped(json, false);
|
|
633
|
+
}
|
|
634
|
+
function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
|
|
635
|
+
return json;
|
|
636
|
+
}
|
|
637
|
+
|
|
629
638
|
// src/types/api/models/FeatureEntitlement.ts
|
|
630
639
|
function FeatureEntitlementFromJSON(json) {
|
|
631
640
|
return FeatureEntitlementFromJSONTyped(json, false);
|
|
@@ -636,22 +645,34 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
636
645
|
}
|
|
637
646
|
return {
|
|
638
647
|
allocation: json["allocation"] == null ? void 0 : json["allocation"],
|
|
648
|
+
consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
|
|
639
649
|
creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
|
|
640
650
|
creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
|
|
651
|
+
creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
|
|
652
|
+
creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
|
|
641
653
|
creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
|
|
642
654
|
creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
|
|
643
655
|
eventName: json["event_name"] == null ? void 0 : json["event_name"],
|
|
656
|
+
eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
|
|
644
657
|
featureId: json["feature_id"],
|
|
645
658
|
featureKey: json["feature_key"],
|
|
646
|
-
metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
|
|
659
|
+
metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
|
|
647
660
|
metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
|
|
648
|
-
monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
|
|
661
|
+
monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
|
|
649
662
|
softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
|
|
650
663
|
usage: json["usage"] == null ? void 0 : json["usage"],
|
|
651
664
|
valueType: EntitlementValueTypeFromJSON(json["value_type"])
|
|
652
665
|
};
|
|
653
666
|
}
|
|
654
667
|
|
|
668
|
+
// src/types/api/models/RuleType.ts
|
|
669
|
+
function RuleTypeFromJSON(json) {
|
|
670
|
+
return RuleTypeFromJSONTyped(json, false);
|
|
671
|
+
}
|
|
672
|
+
function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
673
|
+
return json;
|
|
674
|
+
}
|
|
675
|
+
|
|
655
676
|
// src/types/api/models/CheckFlagResponseData.ts
|
|
656
677
|
function CheckFlagResponseDataFromJSON(json) {
|
|
657
678
|
return CheckFlagResponseDataFromJSONTyped(json, false);
|
|
@@ -667,13 +688,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
667
688
|
featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
|
|
668
689
|
featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
|
|
669
690
|
featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
|
|
670
|
-
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
|
|
691
|
+
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
|
|
671
692
|
featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
|
|
672
693
|
flag: json["flag"],
|
|
673
694
|
flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
|
|
674
695
|
reason: json["reason"],
|
|
675
696
|
ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
|
|
676
|
-
ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
|
|
697
|
+
ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
|
|
677
698
|
userId: json["user_id"] == null ? void 0 : json["user_id"],
|
|
678
699
|
value: json["value"]
|
|
679
700
|
};
|
|
@@ -693,6 +714,272 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
693
714
|
};
|
|
694
715
|
}
|
|
695
716
|
|
|
717
|
+
// src/types/api/runtime.ts
|
|
718
|
+
var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
|
|
719
|
+
var Configuration = class {
|
|
720
|
+
constructor(configuration = {}) {
|
|
721
|
+
this.configuration = configuration;
|
|
722
|
+
}
|
|
723
|
+
configuration;
|
|
724
|
+
set config(configuration) {
|
|
725
|
+
this.configuration = configuration;
|
|
726
|
+
}
|
|
727
|
+
get basePath() {
|
|
728
|
+
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
|
729
|
+
}
|
|
730
|
+
get fetchApi() {
|
|
731
|
+
return this.configuration.fetchApi;
|
|
732
|
+
}
|
|
733
|
+
get middleware() {
|
|
734
|
+
return this.configuration.middleware || [];
|
|
735
|
+
}
|
|
736
|
+
get queryParamsStringify() {
|
|
737
|
+
return this.configuration.queryParamsStringify || querystring;
|
|
738
|
+
}
|
|
739
|
+
get username() {
|
|
740
|
+
return this.configuration.username;
|
|
741
|
+
}
|
|
742
|
+
get password() {
|
|
743
|
+
return this.configuration.password;
|
|
744
|
+
}
|
|
745
|
+
get apiKey() {
|
|
746
|
+
const apiKey = this.configuration.apiKey;
|
|
747
|
+
if (apiKey) {
|
|
748
|
+
return typeof apiKey === "function" ? apiKey : () => apiKey;
|
|
749
|
+
}
|
|
750
|
+
return void 0;
|
|
751
|
+
}
|
|
752
|
+
get accessToken() {
|
|
753
|
+
const accessToken = this.configuration.accessToken;
|
|
754
|
+
if (accessToken) {
|
|
755
|
+
return typeof accessToken === "function" ? accessToken : async () => accessToken;
|
|
756
|
+
}
|
|
757
|
+
return void 0;
|
|
758
|
+
}
|
|
759
|
+
get headers() {
|
|
760
|
+
return this.configuration.headers;
|
|
761
|
+
}
|
|
762
|
+
get credentials() {
|
|
763
|
+
return this.configuration.credentials;
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
var DefaultConfig = new Configuration();
|
|
767
|
+
var BaseAPI = class _BaseAPI {
|
|
768
|
+
constructor(configuration = DefaultConfig) {
|
|
769
|
+
this.configuration = configuration;
|
|
770
|
+
this.middleware = configuration.middleware;
|
|
771
|
+
}
|
|
772
|
+
configuration;
|
|
773
|
+
static jsonRegex = new RegExp(
|
|
774
|
+
"^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
|
|
775
|
+
"i"
|
|
776
|
+
);
|
|
777
|
+
middleware;
|
|
778
|
+
withMiddleware(...middlewares) {
|
|
779
|
+
const next = this.clone();
|
|
780
|
+
next.middleware = next.middleware.concat(...middlewares);
|
|
781
|
+
return next;
|
|
782
|
+
}
|
|
783
|
+
withPreMiddleware(...preMiddlewares) {
|
|
784
|
+
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
|
785
|
+
return this.withMiddleware(...middlewares);
|
|
786
|
+
}
|
|
787
|
+
withPostMiddleware(...postMiddlewares) {
|
|
788
|
+
const middlewares = postMiddlewares.map((post) => ({ post }));
|
|
789
|
+
return this.withMiddleware(...middlewares);
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Check if the given MIME is a JSON MIME.
|
|
793
|
+
* JSON MIME examples:
|
|
794
|
+
* application/json
|
|
795
|
+
* application/json; charset=UTF8
|
|
796
|
+
* APPLICATION/JSON
|
|
797
|
+
* application/vnd.company+json
|
|
798
|
+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
|
799
|
+
* @return True if the given MIME is JSON, false otherwise.
|
|
800
|
+
*/
|
|
801
|
+
isJsonMime(mime) {
|
|
802
|
+
if (!mime) {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
return _BaseAPI.jsonRegex.test(mime);
|
|
806
|
+
}
|
|
807
|
+
async request(context, initOverrides) {
|
|
808
|
+
const { url, init } = await this.createFetchParams(context, initOverrides);
|
|
809
|
+
const response = await this.fetchApi(url, init);
|
|
810
|
+
if (response && response.status >= 200 && response.status < 300) {
|
|
811
|
+
return response;
|
|
812
|
+
}
|
|
813
|
+
throw new ResponseError(response, "Response returned an error code");
|
|
814
|
+
}
|
|
815
|
+
async createFetchParams(context, initOverrides) {
|
|
816
|
+
let url = this.configuration.basePath + context.path;
|
|
817
|
+
if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
|
|
818
|
+
url += "?" + this.configuration.queryParamsStringify(context.query);
|
|
819
|
+
}
|
|
820
|
+
const headers = Object.assign(
|
|
821
|
+
{},
|
|
822
|
+
this.configuration.headers,
|
|
823
|
+
context.headers
|
|
824
|
+
);
|
|
825
|
+
Object.keys(headers).forEach(
|
|
826
|
+
(key) => headers[key] === void 0 ? delete headers[key] : {}
|
|
827
|
+
);
|
|
828
|
+
const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
|
|
829
|
+
const initParams = {
|
|
830
|
+
method: context.method,
|
|
831
|
+
headers,
|
|
832
|
+
body: context.body,
|
|
833
|
+
credentials: this.configuration.credentials
|
|
834
|
+
};
|
|
835
|
+
const overriddenInit = {
|
|
836
|
+
...initParams,
|
|
837
|
+
...await initOverrideFn({
|
|
838
|
+
init: initParams,
|
|
839
|
+
context
|
|
840
|
+
})
|
|
841
|
+
};
|
|
842
|
+
let body;
|
|
843
|
+
if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
|
|
844
|
+
body = overriddenInit.body;
|
|
845
|
+
} else if (this.isJsonMime(headers["Content-Type"])) {
|
|
846
|
+
body = JSON.stringify(overriddenInit.body);
|
|
847
|
+
} else {
|
|
848
|
+
body = overriddenInit.body;
|
|
849
|
+
}
|
|
850
|
+
const init = {
|
|
851
|
+
...overriddenInit,
|
|
852
|
+
body
|
|
853
|
+
};
|
|
854
|
+
return { url, init };
|
|
855
|
+
}
|
|
856
|
+
fetchApi = async (url, init) => {
|
|
857
|
+
let fetchParams = { url, init };
|
|
858
|
+
for (const middleware of this.middleware) {
|
|
859
|
+
if (middleware.pre) {
|
|
860
|
+
fetchParams = await middleware.pre({
|
|
861
|
+
fetch: this.fetchApi,
|
|
862
|
+
...fetchParams
|
|
863
|
+
}) || fetchParams;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
let response = void 0;
|
|
867
|
+
try {
|
|
868
|
+
response = await (this.configuration.fetchApi || fetch)(
|
|
869
|
+
fetchParams.url,
|
|
870
|
+
fetchParams.init
|
|
871
|
+
);
|
|
872
|
+
} catch (e) {
|
|
873
|
+
for (const middleware of this.middleware) {
|
|
874
|
+
if (middleware.onError) {
|
|
875
|
+
response = await middleware.onError({
|
|
876
|
+
fetch: this.fetchApi,
|
|
877
|
+
url: fetchParams.url,
|
|
878
|
+
init: fetchParams.init,
|
|
879
|
+
error: e,
|
|
880
|
+
response: response ? response.clone() : void 0
|
|
881
|
+
}) || response;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
if (response === void 0) {
|
|
885
|
+
if (e instanceof Error) {
|
|
886
|
+
throw new FetchError(
|
|
887
|
+
e,
|
|
888
|
+
"The request failed and the interceptors did not return an alternative response"
|
|
889
|
+
);
|
|
890
|
+
} else {
|
|
891
|
+
throw e;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
for (const middleware of this.middleware) {
|
|
896
|
+
if (middleware.post) {
|
|
897
|
+
response = await middleware.post({
|
|
898
|
+
fetch: this.fetchApi,
|
|
899
|
+
url: fetchParams.url,
|
|
900
|
+
init: fetchParams.init,
|
|
901
|
+
response: response.clone()
|
|
902
|
+
}) || response;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return response;
|
|
906
|
+
};
|
|
907
|
+
/**
|
|
908
|
+
* Create a shallow clone of `this` by constructing a new instance
|
|
909
|
+
* and then shallow cloning data members.
|
|
910
|
+
*/
|
|
911
|
+
clone() {
|
|
912
|
+
const constructor = this.constructor;
|
|
913
|
+
const next = new constructor(this.configuration);
|
|
914
|
+
next.middleware = this.middleware.slice();
|
|
915
|
+
return next;
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
function isBlob(value) {
|
|
919
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
920
|
+
}
|
|
921
|
+
function isFormData(value) {
|
|
922
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
923
|
+
}
|
|
924
|
+
var ResponseError = class extends Error {
|
|
925
|
+
constructor(response, msg) {
|
|
926
|
+
super(msg);
|
|
927
|
+
this.response = response;
|
|
928
|
+
}
|
|
929
|
+
response;
|
|
930
|
+
name = "ResponseError";
|
|
931
|
+
};
|
|
932
|
+
var FetchError = class extends Error {
|
|
933
|
+
constructor(cause, msg) {
|
|
934
|
+
super(msg);
|
|
935
|
+
this.cause = cause;
|
|
936
|
+
}
|
|
937
|
+
cause;
|
|
938
|
+
name = "FetchError";
|
|
939
|
+
};
|
|
940
|
+
function querystring(params, prefix = "") {
|
|
941
|
+
return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
|
|
942
|
+
}
|
|
943
|
+
function querystringSingleKey(key, value, keyPrefix = "") {
|
|
944
|
+
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
|
945
|
+
if (value instanceof Array) {
|
|
946
|
+
const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
|
|
947
|
+
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
|
948
|
+
}
|
|
949
|
+
if (value instanceof Set) {
|
|
950
|
+
const valueAsArray = Array.from(value);
|
|
951
|
+
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
|
952
|
+
}
|
|
953
|
+
if (value instanceof Date) {
|
|
954
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
|
955
|
+
}
|
|
956
|
+
if (value instanceof Object) {
|
|
957
|
+
return querystring(value, fullKey);
|
|
958
|
+
}
|
|
959
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
|
960
|
+
}
|
|
961
|
+
function mapValues(data, fn) {
|
|
962
|
+
return Object.keys(data).reduce(
|
|
963
|
+
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
|
964
|
+
{}
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/types/api/models/CompanyCreditBalance.ts
|
|
969
|
+
function CompanyCreditBalanceFromJSON(json) {
|
|
970
|
+
return CompanyCreditBalanceFromJSONTyped(json, false);
|
|
971
|
+
}
|
|
972
|
+
function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
|
|
973
|
+
if (json == null) {
|
|
974
|
+
return json;
|
|
975
|
+
}
|
|
976
|
+
return {
|
|
977
|
+
remaining: json["remaining"],
|
|
978
|
+
reserved: json["reserved"],
|
|
979
|
+
settled: json["settled"]
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
696
983
|
// src/types/api/models/TrialStatus.ts
|
|
697
984
|
var TrialStatus = {
|
|
698
985
|
Active: "active",
|
|
@@ -731,6 +1018,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
731
1018
|
return json;
|
|
732
1019
|
}
|
|
733
1020
|
return {
|
|
1021
|
+
creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
|
|
734
1022
|
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
735
1023
|
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
736
1024
|
};
|
|
@@ -793,6 +1081,7 @@ var UsagePeriod = /* @__PURE__ */ ((UsagePeriod2) => {
|
|
|
793
1081
|
var CheckFlagReturnFromJSON = (json) => {
|
|
794
1082
|
const {
|
|
795
1083
|
companyId,
|
|
1084
|
+
entitlement,
|
|
796
1085
|
error,
|
|
797
1086
|
featureAllocation,
|
|
798
1087
|
featureUsage,
|
|
@@ -810,20 +1099,30 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
810
1099
|
const featureUsageExceeded = !value && // if flag is not false, then we haven't exceeded usage
|
|
811
1100
|
(ruleType == "company_override_usage_exceeded" /* COMPANY_OVERRIDE_USAGE_EXCEEDED */ || // if the rule type is one of these, then we have exceeded usage
|
|
812
1101
|
ruleType == "plan_entitlement_usage_exceeded" /* PLAN_ENTITLEMENT_USAGE_EXCEEDED */);
|
|
1102
|
+
const resolvedAllocation = entitlement?.allocation ?? featureAllocation;
|
|
1103
|
+
const resolvedUsage = entitlement?.usage ?? featureUsage;
|
|
1104
|
+
const resolvedEvent = entitlement?.eventName ?? featureUsageEvent;
|
|
1105
|
+
const resolvedPeriod = entitlement?.metricPeriod ?? featureUsagePeriod;
|
|
1106
|
+
const resolvedResetAt = entitlement?.metricResetAt ?? featureUsageResetAt;
|
|
813
1107
|
return {
|
|
814
1108
|
featureUsageExceeded,
|
|
815
1109
|
companyId: companyId == null ? void 0 : companyId,
|
|
1110
|
+
creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
|
|
1111
|
+
creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
|
|
1112
|
+
creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
|
|
1113
|
+
creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
|
|
816
1114
|
error: error == null ? void 0 : error,
|
|
817
|
-
featureAllocation:
|
|
818
|
-
featureUsage:
|
|
819
|
-
featureUsageEvent:
|
|
820
|
-
featureUsagePeriod:
|
|
821
|
-
featureUsageResetAt:
|
|
1115
|
+
featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
|
|
1116
|
+
featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
|
|
1117
|
+
featureUsageEvent: resolvedEvent == null ? void 0 : resolvedEvent,
|
|
1118
|
+
featureUsagePeriod: resolvedPeriod == null ? void 0 : resolvedPeriod,
|
|
1119
|
+
featureUsageResetAt: resolvedResetAt == null ? void 0 : resolvedResetAt,
|
|
822
1120
|
flag,
|
|
823
1121
|
flagId: flagId == null ? void 0 : flagId,
|
|
824
1122
|
reason,
|
|
825
1123
|
ruleId: ruleId == null ? void 0 : ruleId,
|
|
826
1124
|
ruleType: ruleType == null ? void 0 : ruleType,
|
|
1125
|
+
softLimit: entitlement?.softLimit == null ? void 0 : entitlement.softLimit,
|
|
827
1126
|
userId: userId == null ? void 0 : userId,
|
|
828
1127
|
value
|
|
829
1128
|
};
|
|
@@ -837,6 +1136,24 @@ var CheckPlanReturnFromJSON = (json) => {
|
|
|
837
1136
|
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
838
1137
|
};
|
|
839
1138
|
};
|
|
1139
|
+
var CreditBalancesFromJSON = (json) => {
|
|
1140
|
+
if (json == null || typeof json !== "object") {
|
|
1141
|
+
return {};
|
|
1142
|
+
}
|
|
1143
|
+
const balances = {};
|
|
1144
|
+
for (const [creditId, raw] of Object.entries(json)) {
|
|
1145
|
+
if (raw == null || typeof raw !== "object") continue;
|
|
1146
|
+
const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
|
|
1147
|
+
if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
balances[creditId] = { remaining, reserved, settled };
|
|
1151
|
+
}
|
|
1152
|
+
return balances;
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
// src/cacheVersion.ts
|
|
1156
|
+
var cacheVersion = "bb56e75d";
|
|
840
1157
|
|
|
841
1158
|
// src/utils.ts
|
|
842
1159
|
function contextString(context) {
|
|
@@ -855,10 +1172,14 @@ function contextString(context) {
|
|
|
855
1172
|
}
|
|
856
1173
|
|
|
857
1174
|
// src/version.ts
|
|
858
|
-
var version = "1.
|
|
1175
|
+
var version = "1.5.0";
|
|
859
1176
|
|
|
860
1177
|
// src/index.ts
|
|
861
1178
|
var anonymousIdKey = "schematicId";
|
|
1179
|
+
var flagStateCachePrefix = "schematicCache";
|
|
1180
|
+
var flagStateCacheMaxContexts = 10;
|
|
1181
|
+
var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1182
|
+
var emptyCreditBalances = Object.freeze({});
|
|
862
1183
|
var Schematic = class {
|
|
863
1184
|
additionalHeaders = {};
|
|
864
1185
|
apiKey;
|
|
@@ -875,11 +1196,17 @@ var Schematic = class {
|
|
|
875
1196
|
isPending = true;
|
|
876
1197
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
877
1198
|
planListeners = /* @__PURE__ */ new Set();
|
|
1199
|
+
creditBalanceListeners = /* @__PURE__ */ new Set();
|
|
878
1200
|
storage;
|
|
1201
|
+
persistFlagState = true;
|
|
1202
|
+
flagStateCacheKey;
|
|
1203
|
+
flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
|
|
1204
|
+
cachedFlagState = null;
|
|
879
1205
|
useWebSocket = false;
|
|
880
1206
|
checks = {};
|
|
881
1207
|
featureUsageEventMap = {};
|
|
882
1208
|
planChecks = {};
|
|
1209
|
+
creditBalances = {};
|
|
883
1210
|
webSocketUrl = "wss://api.schematichq.com";
|
|
884
1211
|
webSocketConnectionTimeout = 1e4;
|
|
885
1212
|
webSocketReconnect = true;
|
|
@@ -908,11 +1235,16 @@ var Schematic = class {
|
|
|
908
1235
|
fallbackCheckCache = {};
|
|
909
1236
|
constructor(apiKey, options) {
|
|
910
1237
|
this.apiKey = apiKey;
|
|
1238
|
+
this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
|
|
911
1239
|
this.eventQueue = [];
|
|
912
1240
|
this.contextDependentEventQueue = [];
|
|
913
1241
|
this.useWebSocket = options?.useWebSocket ?? false;
|
|
914
1242
|
this.debugEnabled = options?.debug ?? false;
|
|
915
1243
|
this.offlineEnabled = options?.offline ?? false;
|
|
1244
|
+
this.persistFlagState = options?.persistFlagState ?? true;
|
|
1245
|
+
if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
|
|
1246
|
+
this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
|
|
1247
|
+
}
|
|
916
1248
|
if (typeof window !== "undefined" && typeof window.location !== "undefined") {
|
|
917
1249
|
const params = new URLSearchParams(window.location.search);
|
|
918
1250
|
const debugParam = params.get("schematic_debug");
|
|
@@ -945,6 +1277,7 @@ var Schematic = class {
|
|
|
945
1277
|
} catch {
|
|
946
1278
|
}
|
|
947
1279
|
}
|
|
1280
|
+
this.hydrateFlagStateFromCache();
|
|
948
1281
|
if (options?.apiUrl !== void 0) {
|
|
949
1282
|
this.apiUrl = options.apiUrl;
|
|
950
1283
|
}
|
|
@@ -1238,6 +1571,29 @@ var Schematic = class {
|
|
|
1238
1571
|
});
|
|
1239
1572
|
this.notifyPlanListeners(plan);
|
|
1240
1573
|
}
|
|
1574
|
+
if (message.credit_balances !== void 0 && message.credit_balances !== null) {
|
|
1575
|
+
const contextStr = contextString(context);
|
|
1576
|
+
const updates = CreditBalancesFromJSON(message.credit_balances);
|
|
1577
|
+
const previous = this.creditBalances[contextStr] ?? {};
|
|
1578
|
+
let changed = false;
|
|
1579
|
+
const merged = { ...previous };
|
|
1580
|
+
for (const [creditId, next] of Object.entries(updates)) {
|
|
1581
|
+
const current = previous[creditId];
|
|
1582
|
+
if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
|
|
1583
|
+
merged[creditId] = next;
|
|
1584
|
+
changed = true;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
if (changed) {
|
|
1588
|
+
this.creditBalances[contextStr] = merged;
|
|
1589
|
+
this.debug(
|
|
1590
|
+
`WebSocket credit balance update received. Notifying listeners`,
|
|
1591
|
+
{ creditBalances: merged }
|
|
1592
|
+
);
|
|
1593
|
+
this.notifyCreditBalanceListeners(merged);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
this.persistContextToCache(contextString(context));
|
|
1241
1597
|
this.flushContextDependentEventQueue();
|
|
1242
1598
|
this.setIsPending(false);
|
|
1243
1599
|
};
|
|
@@ -1345,7 +1701,32 @@ var Schematic = class {
|
|
|
1345
1701
|
return;
|
|
1346
1702
|
}
|
|
1347
1703
|
try {
|
|
1348
|
-
|
|
1704
|
+
const newContextStr = contextString(context);
|
|
1705
|
+
const cacheHit = this.hasCachedValuesForContext(newContextStr);
|
|
1706
|
+
if (cacheHit) {
|
|
1707
|
+
this.debug(
|
|
1708
|
+
`setContext: cache hit for context, pre-resolving from cached values`
|
|
1709
|
+
);
|
|
1710
|
+
this.context = context;
|
|
1711
|
+
this.flushContextDependentEventQueue();
|
|
1712
|
+
this.setIsPending(false);
|
|
1713
|
+
const cachedChecks = this.checks[newContextStr] ?? {};
|
|
1714
|
+
for (const [flagKey, check] of Object.entries(cachedChecks)) {
|
|
1715
|
+
if (check === void 0) continue;
|
|
1716
|
+
this.notifyFlagCheckListeners(flagKey, check);
|
|
1717
|
+
this.notifyFlagValueListeners(flagKey, check.value);
|
|
1718
|
+
}
|
|
1719
|
+
const cachedPlan = this.planChecks[newContextStr];
|
|
1720
|
+
if (cachedPlan !== void 0) {
|
|
1721
|
+
this.notifyPlanListeners(cachedPlan);
|
|
1722
|
+
}
|
|
1723
|
+
const cachedCreditBalances = this.creditBalances[newContextStr];
|
|
1724
|
+
if (cachedCreditBalances !== void 0) {
|
|
1725
|
+
this.notifyCreditBalanceListeners(cachedCreditBalances);
|
|
1726
|
+
}
|
|
1727
|
+
} else {
|
|
1728
|
+
this.setIsPending(true);
|
|
1729
|
+
}
|
|
1349
1730
|
if (!this.conn) {
|
|
1350
1731
|
if (this.isConnecting) {
|
|
1351
1732
|
this.debug(
|
|
@@ -1356,7 +1737,7 @@ var Schematic = class {
|
|
|
1356
1737
|
}
|
|
1357
1738
|
if (this.conn !== null) {
|
|
1358
1739
|
const socket2 = await this.conn;
|
|
1359
|
-
await this.wsSendMessage(socket2, context);
|
|
1740
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1360
1741
|
return;
|
|
1361
1742
|
}
|
|
1362
1743
|
}
|
|
@@ -1372,7 +1753,7 @@ var Schematic = class {
|
|
|
1372
1753
|
this.conn = this.wsConnect();
|
|
1373
1754
|
const socket2 = await this.conn;
|
|
1374
1755
|
this.isConnecting = false;
|
|
1375
|
-
await this.wsSendMessage(socket2, context);
|
|
1756
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1376
1757
|
return;
|
|
1377
1758
|
} catch (error) {
|
|
1378
1759
|
this.isConnecting = false;
|
|
@@ -1380,7 +1761,7 @@ var Schematic = class {
|
|
|
1380
1761
|
}
|
|
1381
1762
|
}
|
|
1382
1763
|
const socket = await this.conn;
|
|
1383
|
-
await this.wsSendMessage(socket, context);
|
|
1764
|
+
await this.wsSendMessage(socket, context, cacheHit);
|
|
1384
1765
|
} catch (error) {
|
|
1385
1766
|
console.warn("Failed to establish WebSocket connection:", error);
|
|
1386
1767
|
this.context = context;
|
|
@@ -1440,10 +1821,12 @@ var Schematic = class {
|
|
|
1440
1821
|
`Optimistically updating feature usage for event: ${eventName}`,
|
|
1441
1822
|
{ quantity }
|
|
1442
1823
|
);
|
|
1824
|
+
let dirty = false;
|
|
1443
1825
|
Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
|
|
1444
1826
|
if (check === void 0) return;
|
|
1445
1827
|
const updatedCheck = { ...check };
|
|
1446
1828
|
if (typeof updatedCheck.featureUsage === "number") {
|
|
1829
|
+
dirty = true;
|
|
1447
1830
|
updatedCheck.featureUsage += quantity;
|
|
1448
1831
|
if (typeof updatedCheck.featureAllocation === "number") {
|
|
1449
1832
|
const wasExceeded = updatedCheck.featureUsageExceeded === true;
|
|
@@ -1473,6 +1856,9 @@ var Schematic = class {
|
|
|
1473
1856
|
this.notifyFlagValueListeners(flagKey, updatedCheck.value);
|
|
1474
1857
|
}
|
|
1475
1858
|
});
|
|
1859
|
+
if (dirty) {
|
|
1860
|
+
this.persistContextToCache(contextString(this.context));
|
|
1861
|
+
}
|
|
1476
1862
|
};
|
|
1477
1863
|
/**
|
|
1478
1864
|
* Event processing
|
|
@@ -1575,6 +1961,206 @@ var Schematic = class {
|
|
|
1575
1961
|
this.storage.setItem(anonymousIdKey, generatedAnonymousId);
|
|
1576
1962
|
return generatedAnonymousId;
|
|
1577
1963
|
};
|
|
1964
|
+
hasCachedValuesForContext = (contextStr) => {
|
|
1965
|
+
const cachedChecks = this.checks[contextStr];
|
|
1966
|
+
if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
|
|
1967
|
+
return true;
|
|
1968
|
+
}
|
|
1969
|
+
if (this.planChecks[contextStr] !== void 0) {
|
|
1970
|
+
return true;
|
|
1971
|
+
}
|
|
1972
|
+
const cachedCreditBalances = this.creditBalances[contextStr];
|
|
1973
|
+
return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
|
|
1974
|
+
};
|
|
1975
|
+
readFlagStateCache = () => {
|
|
1976
|
+
if (!this.persistFlagState || this.storage === void 0) {
|
|
1977
|
+
return null;
|
|
1978
|
+
}
|
|
1979
|
+
let raw;
|
|
1980
|
+
try {
|
|
1981
|
+
raw = this.storage.getItem(this.flagStateCacheKey);
|
|
1982
|
+
} catch (error) {
|
|
1983
|
+
this.debug("Failed to read flag state cache:", error);
|
|
1984
|
+
return null;
|
|
1985
|
+
}
|
|
1986
|
+
if (raw === null || raw === void 0) {
|
|
1987
|
+
return null;
|
|
1988
|
+
}
|
|
1989
|
+
let parsed;
|
|
1990
|
+
try {
|
|
1991
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1992
|
+
} catch (error) {
|
|
1993
|
+
this.debug("Flag state cache is not valid JSON, ignoring:", error);
|
|
1994
|
+
return null;
|
|
1995
|
+
}
|
|
1996
|
+
if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
|
|
1997
|
+
this.debug(
|
|
1998
|
+
`Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
|
|
1999
|
+
{
|
|
2000
|
+
parsedType: typeof parsed,
|
|
2001
|
+
version: parsed?.version
|
|
2002
|
+
}
|
|
2003
|
+
);
|
|
2004
|
+
return null;
|
|
2005
|
+
}
|
|
2006
|
+
return parsed;
|
|
2007
|
+
};
|
|
2008
|
+
reviveCachedCheck = (raw) => {
|
|
2009
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2010
|
+
const obj = raw;
|
|
2011
|
+
if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
|
|
2012
|
+
return null;
|
|
2013
|
+
}
|
|
2014
|
+
const revived = { ...obj };
|
|
2015
|
+
if (typeof revived.featureUsageResetAt === "string") {
|
|
2016
|
+
const d = new Date(revived.featureUsageResetAt);
|
|
2017
|
+
revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
|
|
2018
|
+
}
|
|
2019
|
+
return revived;
|
|
2020
|
+
};
|
|
2021
|
+
reviveCachedPlan = (raw) => {
|
|
2022
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2023
|
+
const obj = raw;
|
|
2024
|
+
if (typeof obj.id !== "string" || typeof obj.name !== "string") {
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2027
|
+
const revived = { ...obj };
|
|
2028
|
+
if (typeof revived.trialEndDate === "string") {
|
|
2029
|
+
const d = new Date(revived.trialEndDate);
|
|
2030
|
+
revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
|
|
2031
|
+
}
|
|
2032
|
+
return revived;
|
|
2033
|
+
};
|
|
2034
|
+
reviveCachedCreditBalances = (raw) => {
|
|
2035
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2036
|
+
const revived = {};
|
|
2037
|
+
for (const [creditId, value] of Object.entries(
|
|
2038
|
+
raw
|
|
2039
|
+
)) {
|
|
2040
|
+
if (value === null || typeof value !== "object") continue;
|
|
2041
|
+
const obj = value;
|
|
2042
|
+
if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
revived[creditId] = {
|
|
2046
|
+
remaining: obj.remaining,
|
|
2047
|
+
reserved: obj.reserved,
|
|
2048
|
+
settled: obj.settled
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
return Object.keys(revived).length > 0 ? revived : null;
|
|
2052
|
+
};
|
|
2053
|
+
hydrateFlagStateFromCache = () => {
|
|
2054
|
+
const parsed = this.readFlagStateCache();
|
|
2055
|
+
if (parsed === null) return;
|
|
2056
|
+
const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
|
|
2057
|
+
const fresh = {};
|
|
2058
|
+
let contextsLoaded = 0;
|
|
2059
|
+
let contextsExpired = 0;
|
|
2060
|
+
for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
|
|
2061
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2062
|
+
if (typeof entry.updatedAt !== "number") continue;
|
|
2063
|
+
if (entry.updatedAt < cutoff) {
|
|
2064
|
+
contextsExpired += 1;
|
|
2065
|
+
continue;
|
|
2066
|
+
}
|
|
2067
|
+
const revivedChecks = {};
|
|
2068
|
+
if (entry.checks !== null && typeof entry.checks === "object") {
|
|
2069
|
+
for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
|
|
2070
|
+
const revived = this.reviveCachedCheck(rawCheck);
|
|
2071
|
+
if (revived === null || revived.flag !== flagKey) continue;
|
|
2072
|
+
revivedChecks[flagKey] = revived;
|
|
2073
|
+
if (typeof revived.featureUsageEvent === "string") {
|
|
2074
|
+
this.updateFeatureUsageEventMap(revived);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
if (Object.keys(revivedChecks).length > 0) {
|
|
2078
|
+
this.checks[contextStr] = revivedChecks;
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
let revivedPlan;
|
|
2082
|
+
if (entry.plan !== void 0 && entry.plan !== null) {
|
|
2083
|
+
const p = this.reviveCachedPlan(entry.plan);
|
|
2084
|
+
if (p !== null) {
|
|
2085
|
+
revivedPlan = p;
|
|
2086
|
+
this.planChecks[contextStr] = p;
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
let revivedCreditBalances;
|
|
2090
|
+
if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
|
|
2091
|
+
const balances = this.reviveCachedCreditBalances(entry.creditBalances);
|
|
2092
|
+
if (balances !== null) {
|
|
2093
|
+
revivedCreditBalances = balances;
|
|
2094
|
+
this.creditBalances[contextStr] = balances;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
fresh[contextStr] = {
|
|
2098
|
+
checks: revivedChecks,
|
|
2099
|
+
plan: revivedPlan,
|
|
2100
|
+
creditBalances: revivedCreditBalances,
|
|
2101
|
+
updatedAt: entry.updatedAt
|
|
2102
|
+
};
|
|
2103
|
+
contextsLoaded += 1;
|
|
2104
|
+
}
|
|
2105
|
+
this.cachedFlagState = { version: cacheVersion, contexts: fresh };
|
|
2106
|
+
this.debug(
|
|
2107
|
+
`Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
|
|
2108
|
+
);
|
|
2109
|
+
};
|
|
2110
|
+
persistContextToCache = (contextStr) => {
|
|
2111
|
+
const checksForContext = this.checks[contextStr];
|
|
2112
|
+
const planForContext = this.planChecks[contextStr];
|
|
2113
|
+
const creditBalancesForContext = this.creditBalances[contextStr];
|
|
2114
|
+
if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
|
|
2115
|
+
return;
|
|
2116
|
+
}
|
|
2117
|
+
if (this.cachedFlagState === null) {
|
|
2118
|
+
this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
|
|
2119
|
+
version: cacheVersion,
|
|
2120
|
+
contexts: {}
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
const cleanChecks = {};
|
|
2124
|
+
if (checksForContext !== void 0) {
|
|
2125
|
+
for (const [flagKey, check] of Object.entries(checksForContext)) {
|
|
2126
|
+
if (check !== void 0) cleanChecks[flagKey] = check;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
this.cachedFlagState.contexts[contextStr] = {
|
|
2130
|
+
checks: cleanChecks,
|
|
2131
|
+
plan: planForContext,
|
|
2132
|
+
creditBalances: creditBalancesForContext,
|
|
2133
|
+
updatedAt: Date.now()
|
|
2134
|
+
};
|
|
2135
|
+
const entries = Object.entries(this.cachedFlagState.contexts);
|
|
2136
|
+
if (entries.length > flagStateCacheMaxContexts) {
|
|
2137
|
+
entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
|
2138
|
+
const survivors = entries.slice(0, flagStateCacheMaxContexts);
|
|
2139
|
+
const survivorKeys = new Set(survivors.map(([k]) => k));
|
|
2140
|
+
for (const key of Object.keys(this.checks)) {
|
|
2141
|
+
if (!survivorKeys.has(key)) delete this.checks[key];
|
|
2142
|
+
}
|
|
2143
|
+
for (const key of Object.keys(this.planChecks)) {
|
|
2144
|
+
if (!survivorKeys.has(key)) delete this.planChecks[key];
|
|
2145
|
+
}
|
|
2146
|
+
for (const key of Object.keys(this.creditBalances)) {
|
|
2147
|
+
if (!survivorKeys.has(key)) delete this.creditBalances[key];
|
|
2148
|
+
}
|
|
2149
|
+
this.cachedFlagState = {
|
|
2150
|
+
version: cacheVersion,
|
|
2151
|
+
contexts: Object.fromEntries(survivors)
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
if (!this.persistFlagState || this.storage === void 0) return;
|
|
2155
|
+
try {
|
|
2156
|
+
this.storage.setItem(
|
|
2157
|
+
this.flagStateCacheKey,
|
|
2158
|
+
JSON.stringify(this.cachedFlagState)
|
|
2159
|
+
);
|
|
2160
|
+
} catch (error) {
|
|
2161
|
+
this.debug("Failed to write flag state cache:", error);
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
1578
2164
|
handleEvent = (eventType, eventBody) => {
|
|
1579
2165
|
const event = {
|
|
1580
2166
|
api_key: this.apiKey,
|
|
@@ -1835,6 +2421,9 @@ var Schematic = class {
|
|
|
1835
2421
|
if (this.conn !== null) {
|
|
1836
2422
|
try {
|
|
1837
2423
|
const socket = await this.conn;
|
|
2424
|
+
if (this.currentWebSocket === socket) {
|
|
2425
|
+
this.currentWebSocket = null;
|
|
2426
|
+
}
|
|
1838
2427
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
1839
2428
|
socket.close();
|
|
1840
2429
|
}
|
|
@@ -2000,6 +2589,7 @@ var Schematic = class {
|
|
|
2000
2589
|
this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
|
|
2001
2590
|
let timeoutId = null;
|
|
2002
2591
|
let isResolved = false;
|
|
2592
|
+
let didOpen = false;
|
|
2003
2593
|
timeoutId = setTimeout(() => {
|
|
2004
2594
|
if (!isResolved) {
|
|
2005
2595
|
isResolved = true;
|
|
@@ -2013,6 +2603,7 @@ var Schematic = class {
|
|
|
2013
2603
|
webSocket.onopen = () => {
|
|
2014
2604
|
if (isResolved) return;
|
|
2015
2605
|
isResolved = true;
|
|
2606
|
+
didOpen = true;
|
|
2016
2607
|
if (timeoutId !== null) {
|
|
2017
2608
|
clearTimeout(timeoutId);
|
|
2018
2609
|
}
|
|
@@ -2038,11 +2629,12 @@ var Schematic = class {
|
|
|
2038
2629
|
}
|
|
2039
2630
|
this.debug(`WebSocket connection ${connectionId} closed`);
|
|
2040
2631
|
this.conn = null;
|
|
2632
|
+
const wasCurrent = this.currentWebSocket === webSocket;
|
|
2041
2633
|
if (this.currentWebSocket === webSocket) {
|
|
2042
2634
|
this.currentWebSocket = null;
|
|
2043
2635
|
this.isConnecting = false;
|
|
2044
2636
|
}
|
|
2045
|
-
if (
|
|
2637
|
+
if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
|
|
2046
2638
|
this.attemptReconnect();
|
|
2047
2639
|
}
|
|
2048
2640
|
};
|
|
@@ -2138,6 +2730,16 @@ var Schematic = class {
|
|
|
2138
2730
|
const plan = this.planChecks[contextStr];
|
|
2139
2731
|
return plan;
|
|
2140
2732
|
};
|
|
2733
|
+
/** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
|
|
2734
|
+
getCreditBalances = () => {
|
|
2735
|
+
const contextStr = contextString(this.context);
|
|
2736
|
+
return this.creditBalances[contextStr] ?? emptyCreditBalances;
|
|
2737
|
+
};
|
|
2738
|
+
/** Get the company's lease-aware balance for a single credit type in the current context */
|
|
2739
|
+
getCreditBalance = (creditId) => {
|
|
2740
|
+
const contextStr = contextString(this.context);
|
|
2741
|
+
return this.creditBalances[contextStr]?.[creditId];
|
|
2742
|
+
};
|
|
2141
2743
|
// flag checks state
|
|
2142
2744
|
getFlagCheck = (flagKey) => {
|
|
2143
2745
|
const contextStr = contextString(this.context);
|
|
@@ -2197,6 +2799,13 @@ var Schematic = class {
|
|
|
2197
2799
|
this.planListeners.delete(listener);
|
|
2198
2800
|
};
|
|
2199
2801
|
};
|
|
2802
|
+
/** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
|
|
2803
|
+
addCreditBalanceListener = (listener) => {
|
|
2804
|
+
this.creditBalanceListeners.add(listener);
|
|
2805
|
+
return () => {
|
|
2806
|
+
this.creditBalanceListeners.delete(listener);
|
|
2807
|
+
};
|
|
2808
|
+
};
|
|
2200
2809
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2201
2810
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2202
2811
|
if (listeners.size > 0) {
|
|
@@ -2260,6 +2869,17 @@ var Schematic = class {
|
|
|
2260
2869
|
});
|
|
2261
2870
|
});
|
|
2262
2871
|
};
|
|
2872
|
+
notifyCreditBalanceListeners = (value) => {
|
|
2873
|
+
const listeners = this.creditBalanceListeners ?? [];
|
|
2874
|
+
if (listeners.size > 0) {
|
|
2875
|
+
this.debug(`Notifying ${listeners.size} credit balance listeners`, {
|
|
2876
|
+
value
|
|
2877
|
+
});
|
|
2878
|
+
}
|
|
2879
|
+
listeners.forEach(
|
|
2880
|
+
(listener) => notifyCreditBalanceListener(listener, value)
|
|
2881
|
+
);
|
|
2882
|
+
};
|
|
2263
2883
|
};
|
|
2264
2884
|
var notifyPendingListener = (listener, value) => {
|
|
2265
2885
|
if (listener.length > 0) {
|
|
@@ -2289,11 +2909,19 @@ var notifyPlanListener = (listener, value) => {
|
|
|
2289
2909
|
listener();
|
|
2290
2910
|
}
|
|
2291
2911
|
};
|
|
2912
|
+
var notifyCreditBalanceListener = (listener, value) => {
|
|
2913
|
+
if (listener.length > 0) {
|
|
2914
|
+
listener(value);
|
|
2915
|
+
} else {
|
|
2916
|
+
listener();
|
|
2917
|
+
}
|
|
2918
|
+
};
|
|
2292
2919
|
export {
|
|
2293
2920
|
CheckFlagResponseFromJSON,
|
|
2294
2921
|
CheckFlagReturnFromJSON,
|
|
2295
2922
|
CheckFlagsResponseFromJSON,
|
|
2296
2923
|
CheckPlanReturnFromJSON,
|
|
2924
|
+
CreditBalancesFromJSON,
|
|
2297
2925
|
DatastreamCompanyPlanFromJSON,
|
|
2298
2926
|
EventBodyFlagCheckToJSON,
|
|
2299
2927
|
RuleType,
|