@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.cjs.js
CHANGED
|
@@ -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 __export = (target, all) => {
|
|
12
16
|
for (var name in all)
|
|
@@ -573,6 +577,7 @@ __export(index_exports, {
|
|
|
573
577
|
CheckFlagReturnFromJSON: () => CheckFlagReturnFromJSON,
|
|
574
578
|
CheckFlagsResponseFromJSON: () => CheckFlagsResponseFromJSON,
|
|
575
579
|
CheckPlanReturnFromJSON: () => CheckPlanReturnFromJSON,
|
|
580
|
+
CreditBalancesFromJSON: () => CreditBalancesFromJSON,
|
|
576
581
|
DatastreamCompanyPlanFromJSON: () => DatastreamCompanyPlanFromJSON,
|
|
577
582
|
EventBodyFlagCheckToJSON: () => EventBodyFlagCheckToJSON,
|
|
578
583
|
RuleType: () => RuleType,
|
|
@@ -592,23 +597,18 @@ function unsafeStringify(arr, offset = 0) {
|
|
|
592
597
|
}
|
|
593
598
|
|
|
594
599
|
// node_modules/uuid/dist/rng.js
|
|
595
|
-
var getRandomValues;
|
|
596
600
|
var rnds8 = new Uint8Array(16);
|
|
597
601
|
function rng() {
|
|
598
|
-
|
|
599
|
-
if (typeof crypto === "undefined" || !crypto.getRandomValues) {
|
|
600
|
-
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
601
|
-
}
|
|
602
|
-
getRandomValues = crypto.getRandomValues.bind(crypto);
|
|
603
|
-
}
|
|
604
|
-
return getRandomValues(rnds8);
|
|
602
|
+
return crypto.getRandomValues(rnds8);
|
|
605
603
|
}
|
|
606
604
|
|
|
607
|
-
// node_modules/uuid/dist/native.js
|
|
608
|
-
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
609
|
-
var native_default = { randomUUID };
|
|
610
|
-
|
|
611
605
|
// node_modules/uuid/dist/v4.js
|
|
606
|
+
function v4(options, buf, offset) {
|
|
607
|
+
if (!buf && !options && crypto.randomUUID) {
|
|
608
|
+
return crypto.randomUUID();
|
|
609
|
+
}
|
|
610
|
+
return _v4(options, buf, offset);
|
|
611
|
+
}
|
|
612
612
|
function _v4(options, buf, offset) {
|
|
613
613
|
options = options || {};
|
|
614
614
|
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
@@ -629,12 +629,6 @@ function _v4(options, buf, offset) {
|
|
|
629
629
|
}
|
|
630
630
|
return unsafeStringify(rnds);
|
|
631
631
|
}
|
|
632
|
-
function v4(options, buf, offset) {
|
|
633
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
634
|
-
return native_default.randomUUID();
|
|
635
|
-
}
|
|
636
|
-
return _v4(options, buf, offset);
|
|
637
|
-
}
|
|
638
632
|
var v4_default = v4;
|
|
639
633
|
|
|
640
634
|
// src/index.ts
|
|
@@ -648,6 +642,22 @@ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
648
642
|
return json;
|
|
649
643
|
}
|
|
650
644
|
|
|
645
|
+
// src/types/api/models/MetricPeriodMonthReset.ts
|
|
646
|
+
function MetricPeriodMonthResetFromJSON(json) {
|
|
647
|
+
return MetricPeriodMonthResetFromJSONTyped(json, false);
|
|
648
|
+
}
|
|
649
|
+
function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
|
|
650
|
+
return json;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// src/types/api/models/MetricPeriod.ts
|
|
654
|
+
function MetricPeriodFromJSON(json) {
|
|
655
|
+
return MetricPeriodFromJSONTyped(json, false);
|
|
656
|
+
}
|
|
657
|
+
function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
|
|
658
|
+
return json;
|
|
659
|
+
}
|
|
660
|
+
|
|
651
661
|
// src/types/api/models/FeatureEntitlement.ts
|
|
652
662
|
function FeatureEntitlementFromJSON(json) {
|
|
653
663
|
return FeatureEntitlementFromJSONTyped(json, false);
|
|
@@ -658,22 +668,34 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
658
668
|
}
|
|
659
669
|
return {
|
|
660
670
|
allocation: json["allocation"] == null ? void 0 : json["allocation"],
|
|
671
|
+
consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
|
|
661
672
|
creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
|
|
662
673
|
creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
|
|
674
|
+
creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
|
|
675
|
+
creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
|
|
663
676
|
creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
|
|
664
677
|
creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
|
|
665
678
|
eventName: json["event_name"] == null ? void 0 : json["event_name"],
|
|
679
|
+
eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
|
|
666
680
|
featureId: json["feature_id"],
|
|
667
681
|
featureKey: json["feature_key"],
|
|
668
|
-
metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
|
|
682
|
+
metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
|
|
669
683
|
metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
|
|
670
|
-
monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
|
|
684
|
+
monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
|
|
671
685
|
softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
|
|
672
686
|
usage: json["usage"] == null ? void 0 : json["usage"],
|
|
673
687
|
valueType: EntitlementValueTypeFromJSON(json["value_type"])
|
|
674
688
|
};
|
|
675
689
|
}
|
|
676
690
|
|
|
691
|
+
// src/types/api/models/RuleType.ts
|
|
692
|
+
function RuleTypeFromJSON(json) {
|
|
693
|
+
return RuleTypeFromJSONTyped(json, false);
|
|
694
|
+
}
|
|
695
|
+
function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
696
|
+
return json;
|
|
697
|
+
}
|
|
698
|
+
|
|
677
699
|
// src/types/api/models/CheckFlagResponseData.ts
|
|
678
700
|
function CheckFlagResponseDataFromJSON(json) {
|
|
679
701
|
return CheckFlagResponseDataFromJSONTyped(json, false);
|
|
@@ -689,13 +711,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
689
711
|
featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
|
|
690
712
|
featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
|
|
691
713
|
featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
|
|
692
|
-
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
|
|
714
|
+
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
|
|
693
715
|
featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
|
|
694
716
|
flag: json["flag"],
|
|
695
717
|
flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
|
|
696
718
|
reason: json["reason"],
|
|
697
719
|
ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
|
|
698
|
-
ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
|
|
720
|
+
ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
|
|
699
721
|
userId: json["user_id"] == null ? void 0 : json["user_id"],
|
|
700
722
|
value: json["value"]
|
|
701
723
|
};
|
|
@@ -715,6 +737,272 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
715
737
|
};
|
|
716
738
|
}
|
|
717
739
|
|
|
740
|
+
// src/types/api/runtime.ts
|
|
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
|
+
|
|
991
|
+
// src/types/api/models/CompanyCreditBalance.ts
|
|
992
|
+
function CompanyCreditBalanceFromJSON(json) {
|
|
993
|
+
return CompanyCreditBalanceFromJSONTyped(json, false);
|
|
994
|
+
}
|
|
995
|
+
function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
|
|
996
|
+
if (json == null) {
|
|
997
|
+
return json;
|
|
998
|
+
}
|
|
999
|
+
return {
|
|
1000
|
+
remaining: json["remaining"],
|
|
1001
|
+
reserved: json["reserved"],
|
|
1002
|
+
settled: json["settled"]
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
|
|
718
1006
|
// src/types/api/models/TrialStatus.ts
|
|
719
1007
|
var TrialStatus = {
|
|
720
1008
|
Active: "active",
|
|
@@ -753,6 +1041,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
753
1041
|
return json;
|
|
754
1042
|
}
|
|
755
1043
|
return {
|
|
1044
|
+
creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
|
|
756
1045
|
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
757
1046
|
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
758
1047
|
};
|
|
@@ -815,6 +1104,7 @@ var UsagePeriod = /* @__PURE__ */ ((UsagePeriod2) => {
|
|
|
815
1104
|
var CheckFlagReturnFromJSON = (json) => {
|
|
816
1105
|
const {
|
|
817
1106
|
companyId,
|
|
1107
|
+
entitlement,
|
|
818
1108
|
error,
|
|
819
1109
|
featureAllocation,
|
|
820
1110
|
featureUsage,
|
|
@@ -832,20 +1122,30 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
832
1122
|
const featureUsageExceeded = !value && // if flag is not false, then we haven't exceeded usage
|
|
833
1123
|
(ruleType == "company_override_usage_exceeded" /* COMPANY_OVERRIDE_USAGE_EXCEEDED */ || // if the rule type is one of these, then we have exceeded usage
|
|
834
1124
|
ruleType == "plan_entitlement_usage_exceeded" /* PLAN_ENTITLEMENT_USAGE_EXCEEDED */);
|
|
1125
|
+
const resolvedAllocation = entitlement?.allocation ?? featureAllocation;
|
|
1126
|
+
const resolvedUsage = entitlement?.usage ?? featureUsage;
|
|
1127
|
+
const resolvedEvent = entitlement?.eventName ?? featureUsageEvent;
|
|
1128
|
+
const resolvedPeriod = entitlement?.metricPeriod ?? featureUsagePeriod;
|
|
1129
|
+
const resolvedResetAt = entitlement?.metricResetAt ?? featureUsageResetAt;
|
|
835
1130
|
return {
|
|
836
1131
|
featureUsageExceeded,
|
|
837
1132
|
companyId: companyId == null ? void 0 : companyId,
|
|
1133
|
+
creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
|
|
1134
|
+
creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
|
|
1135
|
+
creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
|
|
1136
|
+
creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
|
|
838
1137
|
error: error == null ? void 0 : error,
|
|
839
|
-
featureAllocation:
|
|
840
|
-
featureUsage:
|
|
841
|
-
featureUsageEvent:
|
|
842
|
-
featureUsagePeriod:
|
|
843
|
-
featureUsageResetAt:
|
|
1138
|
+
featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
|
|
1139
|
+
featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
|
|
1140
|
+
featureUsageEvent: resolvedEvent == null ? void 0 : resolvedEvent,
|
|
1141
|
+
featureUsagePeriod: resolvedPeriod == null ? void 0 : resolvedPeriod,
|
|
1142
|
+
featureUsageResetAt: resolvedResetAt == null ? void 0 : resolvedResetAt,
|
|
844
1143
|
flag,
|
|
845
1144
|
flagId: flagId == null ? void 0 : flagId,
|
|
846
1145
|
reason,
|
|
847
1146
|
ruleId: ruleId == null ? void 0 : ruleId,
|
|
848
1147
|
ruleType: ruleType == null ? void 0 : ruleType,
|
|
1148
|
+
softLimit: entitlement?.softLimit == null ? void 0 : entitlement.softLimit,
|
|
849
1149
|
userId: userId == null ? void 0 : userId,
|
|
850
1150
|
value
|
|
851
1151
|
};
|
|
@@ -859,6 +1159,24 @@ var CheckPlanReturnFromJSON = (json) => {
|
|
|
859
1159
|
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
860
1160
|
};
|
|
861
1161
|
};
|
|
1162
|
+
var CreditBalancesFromJSON = (json) => {
|
|
1163
|
+
if (json == null || typeof json !== "object") {
|
|
1164
|
+
return {};
|
|
1165
|
+
}
|
|
1166
|
+
const balances = {};
|
|
1167
|
+
for (const [creditId, raw] of Object.entries(json)) {
|
|
1168
|
+
if (raw == null || typeof raw !== "object") continue;
|
|
1169
|
+
const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
|
|
1170
|
+
if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
balances[creditId] = { remaining, reserved, settled };
|
|
1174
|
+
}
|
|
1175
|
+
return balances;
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
// src/cacheVersion.ts
|
|
1179
|
+
var cacheVersion = "bb56e75d";
|
|
862
1180
|
|
|
863
1181
|
// src/utils.ts
|
|
864
1182
|
function contextString(context) {
|
|
@@ -877,10 +1195,14 @@ function contextString(context) {
|
|
|
877
1195
|
}
|
|
878
1196
|
|
|
879
1197
|
// src/version.ts
|
|
880
|
-
var version = "1.
|
|
1198
|
+
var version = "1.5.0";
|
|
881
1199
|
|
|
882
1200
|
// src/index.ts
|
|
883
1201
|
var anonymousIdKey = "schematicId";
|
|
1202
|
+
var flagStateCachePrefix = "schematicCache";
|
|
1203
|
+
var flagStateCacheMaxContexts = 10;
|
|
1204
|
+
var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1205
|
+
var emptyCreditBalances = Object.freeze({});
|
|
884
1206
|
var Schematic = class {
|
|
885
1207
|
additionalHeaders = {};
|
|
886
1208
|
apiKey;
|
|
@@ -897,11 +1219,17 @@ var Schematic = class {
|
|
|
897
1219
|
isPending = true;
|
|
898
1220
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
899
1221
|
planListeners = /* @__PURE__ */ new Set();
|
|
1222
|
+
creditBalanceListeners = /* @__PURE__ */ new Set();
|
|
900
1223
|
storage;
|
|
1224
|
+
persistFlagState = true;
|
|
1225
|
+
flagStateCacheKey;
|
|
1226
|
+
flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
|
|
1227
|
+
cachedFlagState = null;
|
|
901
1228
|
useWebSocket = false;
|
|
902
1229
|
checks = {};
|
|
903
1230
|
featureUsageEventMap = {};
|
|
904
1231
|
planChecks = {};
|
|
1232
|
+
creditBalances = {};
|
|
905
1233
|
webSocketUrl = "wss://api.schematichq.com";
|
|
906
1234
|
webSocketConnectionTimeout = 1e4;
|
|
907
1235
|
webSocketReconnect = true;
|
|
@@ -930,11 +1258,16 @@ var Schematic = class {
|
|
|
930
1258
|
fallbackCheckCache = {};
|
|
931
1259
|
constructor(apiKey, options) {
|
|
932
1260
|
this.apiKey = apiKey;
|
|
1261
|
+
this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
|
|
933
1262
|
this.eventQueue = [];
|
|
934
1263
|
this.contextDependentEventQueue = [];
|
|
935
1264
|
this.useWebSocket = options?.useWebSocket ?? false;
|
|
936
1265
|
this.debugEnabled = options?.debug ?? false;
|
|
937
1266
|
this.offlineEnabled = options?.offline ?? false;
|
|
1267
|
+
this.persistFlagState = options?.persistFlagState ?? true;
|
|
1268
|
+
if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
|
|
1269
|
+
this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
|
|
1270
|
+
}
|
|
938
1271
|
if (typeof window !== "undefined" && typeof window.location !== "undefined") {
|
|
939
1272
|
const params = new URLSearchParams(window.location.search);
|
|
940
1273
|
const debugParam = params.get("schematic_debug");
|
|
@@ -967,6 +1300,7 @@ var Schematic = class {
|
|
|
967
1300
|
} catch {
|
|
968
1301
|
}
|
|
969
1302
|
}
|
|
1303
|
+
this.hydrateFlagStateFromCache();
|
|
970
1304
|
if (options?.apiUrl !== void 0) {
|
|
971
1305
|
this.apiUrl = options.apiUrl;
|
|
972
1306
|
}
|
|
@@ -1260,6 +1594,29 @@ var Schematic = class {
|
|
|
1260
1594
|
});
|
|
1261
1595
|
this.notifyPlanListeners(plan);
|
|
1262
1596
|
}
|
|
1597
|
+
if (message.credit_balances !== void 0 && message.credit_balances !== null) {
|
|
1598
|
+
const contextStr = contextString(context);
|
|
1599
|
+
const updates = CreditBalancesFromJSON(message.credit_balances);
|
|
1600
|
+
const previous = this.creditBalances[contextStr] ?? {};
|
|
1601
|
+
let changed = false;
|
|
1602
|
+
const merged = { ...previous };
|
|
1603
|
+
for (const [creditId, next] of Object.entries(updates)) {
|
|
1604
|
+
const current = previous[creditId];
|
|
1605
|
+
if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
|
|
1606
|
+
merged[creditId] = next;
|
|
1607
|
+
changed = true;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
if (changed) {
|
|
1611
|
+
this.creditBalances[contextStr] = merged;
|
|
1612
|
+
this.debug(
|
|
1613
|
+
`WebSocket credit balance update received. Notifying listeners`,
|
|
1614
|
+
{ creditBalances: merged }
|
|
1615
|
+
);
|
|
1616
|
+
this.notifyCreditBalanceListeners(merged);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
this.persistContextToCache(contextString(context));
|
|
1263
1620
|
this.flushContextDependentEventQueue();
|
|
1264
1621
|
this.setIsPending(false);
|
|
1265
1622
|
};
|
|
@@ -1367,7 +1724,32 @@ var Schematic = class {
|
|
|
1367
1724
|
return;
|
|
1368
1725
|
}
|
|
1369
1726
|
try {
|
|
1370
|
-
|
|
1727
|
+
const newContextStr = contextString(context);
|
|
1728
|
+
const cacheHit = this.hasCachedValuesForContext(newContextStr);
|
|
1729
|
+
if (cacheHit) {
|
|
1730
|
+
this.debug(
|
|
1731
|
+
`setContext: cache hit for context, pre-resolving from cached values`
|
|
1732
|
+
);
|
|
1733
|
+
this.context = context;
|
|
1734
|
+
this.flushContextDependentEventQueue();
|
|
1735
|
+
this.setIsPending(false);
|
|
1736
|
+
const cachedChecks = this.checks[newContextStr] ?? {};
|
|
1737
|
+
for (const [flagKey, check] of Object.entries(cachedChecks)) {
|
|
1738
|
+
if (check === void 0) continue;
|
|
1739
|
+
this.notifyFlagCheckListeners(flagKey, check);
|
|
1740
|
+
this.notifyFlagValueListeners(flagKey, check.value);
|
|
1741
|
+
}
|
|
1742
|
+
const cachedPlan = this.planChecks[newContextStr];
|
|
1743
|
+
if (cachedPlan !== void 0) {
|
|
1744
|
+
this.notifyPlanListeners(cachedPlan);
|
|
1745
|
+
}
|
|
1746
|
+
const cachedCreditBalances = this.creditBalances[newContextStr];
|
|
1747
|
+
if (cachedCreditBalances !== void 0) {
|
|
1748
|
+
this.notifyCreditBalanceListeners(cachedCreditBalances);
|
|
1749
|
+
}
|
|
1750
|
+
} else {
|
|
1751
|
+
this.setIsPending(true);
|
|
1752
|
+
}
|
|
1371
1753
|
if (!this.conn) {
|
|
1372
1754
|
if (this.isConnecting) {
|
|
1373
1755
|
this.debug(
|
|
@@ -1378,7 +1760,7 @@ var Schematic = class {
|
|
|
1378
1760
|
}
|
|
1379
1761
|
if (this.conn !== null) {
|
|
1380
1762
|
const socket2 = await this.conn;
|
|
1381
|
-
await this.wsSendMessage(socket2, context);
|
|
1763
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1382
1764
|
return;
|
|
1383
1765
|
}
|
|
1384
1766
|
}
|
|
@@ -1394,7 +1776,7 @@ var Schematic = class {
|
|
|
1394
1776
|
this.conn = this.wsConnect();
|
|
1395
1777
|
const socket2 = await this.conn;
|
|
1396
1778
|
this.isConnecting = false;
|
|
1397
|
-
await this.wsSendMessage(socket2, context);
|
|
1779
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1398
1780
|
return;
|
|
1399
1781
|
} catch (error) {
|
|
1400
1782
|
this.isConnecting = false;
|
|
@@ -1402,7 +1784,7 @@ var Schematic = class {
|
|
|
1402
1784
|
}
|
|
1403
1785
|
}
|
|
1404
1786
|
const socket = await this.conn;
|
|
1405
|
-
await this.wsSendMessage(socket, context);
|
|
1787
|
+
await this.wsSendMessage(socket, context, cacheHit);
|
|
1406
1788
|
} catch (error) {
|
|
1407
1789
|
console.warn("Failed to establish WebSocket connection:", error);
|
|
1408
1790
|
this.context = context;
|
|
@@ -1462,10 +1844,12 @@ var Schematic = class {
|
|
|
1462
1844
|
`Optimistically updating feature usage for event: ${eventName}`,
|
|
1463
1845
|
{ quantity }
|
|
1464
1846
|
);
|
|
1847
|
+
let dirty = false;
|
|
1465
1848
|
Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
|
|
1466
1849
|
if (check === void 0) return;
|
|
1467
1850
|
const updatedCheck = { ...check };
|
|
1468
1851
|
if (typeof updatedCheck.featureUsage === "number") {
|
|
1852
|
+
dirty = true;
|
|
1469
1853
|
updatedCheck.featureUsage += quantity;
|
|
1470
1854
|
if (typeof updatedCheck.featureAllocation === "number") {
|
|
1471
1855
|
const wasExceeded = updatedCheck.featureUsageExceeded === true;
|
|
@@ -1495,6 +1879,9 @@ var Schematic = class {
|
|
|
1495
1879
|
this.notifyFlagValueListeners(flagKey, updatedCheck.value);
|
|
1496
1880
|
}
|
|
1497
1881
|
});
|
|
1882
|
+
if (dirty) {
|
|
1883
|
+
this.persistContextToCache(contextString(this.context));
|
|
1884
|
+
}
|
|
1498
1885
|
};
|
|
1499
1886
|
/**
|
|
1500
1887
|
* Event processing
|
|
@@ -1597,6 +1984,206 @@ var Schematic = class {
|
|
|
1597
1984
|
this.storage.setItem(anonymousIdKey, generatedAnonymousId);
|
|
1598
1985
|
return generatedAnonymousId;
|
|
1599
1986
|
};
|
|
1987
|
+
hasCachedValuesForContext = (contextStr) => {
|
|
1988
|
+
const cachedChecks = this.checks[contextStr];
|
|
1989
|
+
if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
|
|
1990
|
+
return true;
|
|
1991
|
+
}
|
|
1992
|
+
if (this.planChecks[contextStr] !== void 0) {
|
|
1993
|
+
return true;
|
|
1994
|
+
}
|
|
1995
|
+
const cachedCreditBalances = this.creditBalances[contextStr];
|
|
1996
|
+
return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
|
|
1997
|
+
};
|
|
1998
|
+
readFlagStateCache = () => {
|
|
1999
|
+
if (!this.persistFlagState || this.storage === void 0) {
|
|
2000
|
+
return null;
|
|
2001
|
+
}
|
|
2002
|
+
let raw;
|
|
2003
|
+
try {
|
|
2004
|
+
raw = this.storage.getItem(this.flagStateCacheKey);
|
|
2005
|
+
} catch (error) {
|
|
2006
|
+
this.debug("Failed to read flag state cache:", error);
|
|
2007
|
+
return null;
|
|
2008
|
+
}
|
|
2009
|
+
if (raw === null || raw === void 0) {
|
|
2010
|
+
return null;
|
|
2011
|
+
}
|
|
2012
|
+
let parsed;
|
|
2013
|
+
try {
|
|
2014
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
2015
|
+
} catch (error) {
|
|
2016
|
+
this.debug("Flag state cache is not valid JSON, ignoring:", error);
|
|
2017
|
+
return null;
|
|
2018
|
+
}
|
|
2019
|
+
if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
|
|
2020
|
+
this.debug(
|
|
2021
|
+
`Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
|
|
2022
|
+
{
|
|
2023
|
+
parsedType: typeof parsed,
|
|
2024
|
+
version: parsed?.version
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2027
|
+
return null;
|
|
2028
|
+
}
|
|
2029
|
+
return parsed;
|
|
2030
|
+
};
|
|
2031
|
+
reviveCachedCheck = (raw) => {
|
|
2032
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2033
|
+
const obj = raw;
|
|
2034
|
+
if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
|
|
2035
|
+
return null;
|
|
2036
|
+
}
|
|
2037
|
+
const revived = { ...obj };
|
|
2038
|
+
if (typeof revived.featureUsageResetAt === "string") {
|
|
2039
|
+
const d = new Date(revived.featureUsageResetAt);
|
|
2040
|
+
revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
|
|
2041
|
+
}
|
|
2042
|
+
return revived;
|
|
2043
|
+
};
|
|
2044
|
+
reviveCachedPlan = (raw) => {
|
|
2045
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2046
|
+
const obj = raw;
|
|
2047
|
+
if (typeof obj.id !== "string" || typeof obj.name !== "string") {
|
|
2048
|
+
return null;
|
|
2049
|
+
}
|
|
2050
|
+
const revived = { ...obj };
|
|
2051
|
+
if (typeof revived.trialEndDate === "string") {
|
|
2052
|
+
const d = new Date(revived.trialEndDate);
|
|
2053
|
+
revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
|
|
2054
|
+
}
|
|
2055
|
+
return revived;
|
|
2056
|
+
};
|
|
2057
|
+
reviveCachedCreditBalances = (raw) => {
|
|
2058
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2059
|
+
const revived = {};
|
|
2060
|
+
for (const [creditId, value] of Object.entries(
|
|
2061
|
+
raw
|
|
2062
|
+
)) {
|
|
2063
|
+
if (value === null || typeof value !== "object") continue;
|
|
2064
|
+
const obj = value;
|
|
2065
|
+
if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
revived[creditId] = {
|
|
2069
|
+
remaining: obj.remaining,
|
|
2070
|
+
reserved: obj.reserved,
|
|
2071
|
+
settled: obj.settled
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
return Object.keys(revived).length > 0 ? revived : null;
|
|
2075
|
+
};
|
|
2076
|
+
hydrateFlagStateFromCache = () => {
|
|
2077
|
+
const parsed = this.readFlagStateCache();
|
|
2078
|
+
if (parsed === null) return;
|
|
2079
|
+
const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
|
|
2080
|
+
const fresh = {};
|
|
2081
|
+
let contextsLoaded = 0;
|
|
2082
|
+
let contextsExpired = 0;
|
|
2083
|
+
for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
|
|
2084
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2085
|
+
if (typeof entry.updatedAt !== "number") continue;
|
|
2086
|
+
if (entry.updatedAt < cutoff) {
|
|
2087
|
+
contextsExpired += 1;
|
|
2088
|
+
continue;
|
|
2089
|
+
}
|
|
2090
|
+
const revivedChecks = {};
|
|
2091
|
+
if (entry.checks !== null && typeof entry.checks === "object") {
|
|
2092
|
+
for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
|
|
2093
|
+
const revived = this.reviveCachedCheck(rawCheck);
|
|
2094
|
+
if (revived === null || revived.flag !== flagKey) continue;
|
|
2095
|
+
revivedChecks[flagKey] = revived;
|
|
2096
|
+
if (typeof revived.featureUsageEvent === "string") {
|
|
2097
|
+
this.updateFeatureUsageEventMap(revived);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
if (Object.keys(revivedChecks).length > 0) {
|
|
2101
|
+
this.checks[contextStr] = revivedChecks;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
let revivedPlan;
|
|
2105
|
+
if (entry.plan !== void 0 && entry.plan !== null) {
|
|
2106
|
+
const p = this.reviveCachedPlan(entry.plan);
|
|
2107
|
+
if (p !== null) {
|
|
2108
|
+
revivedPlan = p;
|
|
2109
|
+
this.planChecks[contextStr] = p;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
let revivedCreditBalances;
|
|
2113
|
+
if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
|
|
2114
|
+
const balances = this.reviveCachedCreditBalances(entry.creditBalances);
|
|
2115
|
+
if (balances !== null) {
|
|
2116
|
+
revivedCreditBalances = balances;
|
|
2117
|
+
this.creditBalances[contextStr] = balances;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
fresh[contextStr] = {
|
|
2121
|
+
checks: revivedChecks,
|
|
2122
|
+
plan: revivedPlan,
|
|
2123
|
+
creditBalances: revivedCreditBalances,
|
|
2124
|
+
updatedAt: entry.updatedAt
|
|
2125
|
+
};
|
|
2126
|
+
contextsLoaded += 1;
|
|
2127
|
+
}
|
|
2128
|
+
this.cachedFlagState = { version: cacheVersion, contexts: fresh };
|
|
2129
|
+
this.debug(
|
|
2130
|
+
`Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
|
|
2131
|
+
);
|
|
2132
|
+
};
|
|
2133
|
+
persistContextToCache = (contextStr) => {
|
|
2134
|
+
const checksForContext = this.checks[contextStr];
|
|
2135
|
+
const planForContext = this.planChecks[contextStr];
|
|
2136
|
+
const creditBalancesForContext = this.creditBalances[contextStr];
|
|
2137
|
+
if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
if (this.cachedFlagState === null) {
|
|
2141
|
+
this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
|
|
2142
|
+
version: cacheVersion,
|
|
2143
|
+
contexts: {}
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
const cleanChecks = {};
|
|
2147
|
+
if (checksForContext !== void 0) {
|
|
2148
|
+
for (const [flagKey, check] of Object.entries(checksForContext)) {
|
|
2149
|
+
if (check !== void 0) cleanChecks[flagKey] = check;
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
this.cachedFlagState.contexts[contextStr] = {
|
|
2153
|
+
checks: cleanChecks,
|
|
2154
|
+
plan: planForContext,
|
|
2155
|
+
creditBalances: creditBalancesForContext,
|
|
2156
|
+
updatedAt: Date.now()
|
|
2157
|
+
};
|
|
2158
|
+
const entries = Object.entries(this.cachedFlagState.contexts);
|
|
2159
|
+
if (entries.length > flagStateCacheMaxContexts) {
|
|
2160
|
+
entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
|
2161
|
+
const survivors = entries.slice(0, flagStateCacheMaxContexts);
|
|
2162
|
+
const survivorKeys = new Set(survivors.map(([k]) => k));
|
|
2163
|
+
for (const key of Object.keys(this.checks)) {
|
|
2164
|
+
if (!survivorKeys.has(key)) delete this.checks[key];
|
|
2165
|
+
}
|
|
2166
|
+
for (const key of Object.keys(this.planChecks)) {
|
|
2167
|
+
if (!survivorKeys.has(key)) delete this.planChecks[key];
|
|
2168
|
+
}
|
|
2169
|
+
for (const key of Object.keys(this.creditBalances)) {
|
|
2170
|
+
if (!survivorKeys.has(key)) delete this.creditBalances[key];
|
|
2171
|
+
}
|
|
2172
|
+
this.cachedFlagState = {
|
|
2173
|
+
version: cacheVersion,
|
|
2174
|
+
contexts: Object.fromEntries(survivors)
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
if (!this.persistFlagState || this.storage === void 0) return;
|
|
2178
|
+
try {
|
|
2179
|
+
this.storage.setItem(
|
|
2180
|
+
this.flagStateCacheKey,
|
|
2181
|
+
JSON.stringify(this.cachedFlagState)
|
|
2182
|
+
);
|
|
2183
|
+
} catch (error) {
|
|
2184
|
+
this.debug("Failed to write flag state cache:", error);
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
1600
2187
|
handleEvent = (eventType, eventBody) => {
|
|
1601
2188
|
const event = {
|
|
1602
2189
|
api_key: this.apiKey,
|
|
@@ -1857,6 +2444,9 @@ var Schematic = class {
|
|
|
1857
2444
|
if (this.conn !== null) {
|
|
1858
2445
|
try {
|
|
1859
2446
|
const socket = await this.conn;
|
|
2447
|
+
if (this.currentWebSocket === socket) {
|
|
2448
|
+
this.currentWebSocket = null;
|
|
2449
|
+
}
|
|
1860
2450
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
1861
2451
|
socket.close();
|
|
1862
2452
|
}
|
|
@@ -2022,6 +2612,7 @@ var Schematic = class {
|
|
|
2022
2612
|
this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
|
|
2023
2613
|
let timeoutId = null;
|
|
2024
2614
|
let isResolved = false;
|
|
2615
|
+
let didOpen = false;
|
|
2025
2616
|
timeoutId = setTimeout(() => {
|
|
2026
2617
|
if (!isResolved) {
|
|
2027
2618
|
isResolved = true;
|
|
@@ -2035,6 +2626,7 @@ var Schematic = class {
|
|
|
2035
2626
|
webSocket.onopen = () => {
|
|
2036
2627
|
if (isResolved) return;
|
|
2037
2628
|
isResolved = true;
|
|
2629
|
+
didOpen = true;
|
|
2038
2630
|
if (timeoutId !== null) {
|
|
2039
2631
|
clearTimeout(timeoutId);
|
|
2040
2632
|
}
|
|
@@ -2060,11 +2652,12 @@ var Schematic = class {
|
|
|
2060
2652
|
}
|
|
2061
2653
|
this.debug(`WebSocket connection ${connectionId} closed`);
|
|
2062
2654
|
this.conn = null;
|
|
2655
|
+
const wasCurrent = this.currentWebSocket === webSocket;
|
|
2063
2656
|
if (this.currentWebSocket === webSocket) {
|
|
2064
2657
|
this.currentWebSocket = null;
|
|
2065
2658
|
this.isConnecting = false;
|
|
2066
2659
|
}
|
|
2067
|
-
if (
|
|
2660
|
+
if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
|
|
2068
2661
|
this.attemptReconnect();
|
|
2069
2662
|
}
|
|
2070
2663
|
};
|
|
@@ -2160,6 +2753,16 @@ var Schematic = class {
|
|
|
2160
2753
|
const plan = this.planChecks[contextStr];
|
|
2161
2754
|
return plan;
|
|
2162
2755
|
};
|
|
2756
|
+
/** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
|
|
2757
|
+
getCreditBalances = () => {
|
|
2758
|
+
const contextStr = contextString(this.context);
|
|
2759
|
+
return this.creditBalances[contextStr] ?? emptyCreditBalances;
|
|
2760
|
+
};
|
|
2761
|
+
/** Get the company's lease-aware balance for a single credit type in the current context */
|
|
2762
|
+
getCreditBalance = (creditId) => {
|
|
2763
|
+
const contextStr = contextString(this.context);
|
|
2764
|
+
return this.creditBalances[contextStr]?.[creditId];
|
|
2765
|
+
};
|
|
2163
2766
|
// flag checks state
|
|
2164
2767
|
getFlagCheck = (flagKey) => {
|
|
2165
2768
|
const contextStr = contextString(this.context);
|
|
@@ -2219,6 +2822,13 @@ var Schematic = class {
|
|
|
2219
2822
|
this.planListeners.delete(listener);
|
|
2220
2823
|
};
|
|
2221
2824
|
};
|
|
2825
|
+
/** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
|
|
2826
|
+
addCreditBalanceListener = (listener) => {
|
|
2827
|
+
this.creditBalanceListeners.add(listener);
|
|
2828
|
+
return () => {
|
|
2829
|
+
this.creditBalanceListeners.delete(listener);
|
|
2830
|
+
};
|
|
2831
|
+
};
|
|
2222
2832
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2223
2833
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2224
2834
|
if (listeners.size > 0) {
|
|
@@ -2282,6 +2892,17 @@ var Schematic = class {
|
|
|
2282
2892
|
});
|
|
2283
2893
|
});
|
|
2284
2894
|
};
|
|
2895
|
+
notifyCreditBalanceListeners = (value) => {
|
|
2896
|
+
const listeners = this.creditBalanceListeners ?? [];
|
|
2897
|
+
if (listeners.size > 0) {
|
|
2898
|
+
this.debug(`Notifying ${listeners.size} credit balance listeners`, {
|
|
2899
|
+
value
|
|
2900
|
+
});
|
|
2901
|
+
}
|
|
2902
|
+
listeners.forEach(
|
|
2903
|
+
(listener) => notifyCreditBalanceListener(listener, value)
|
|
2904
|
+
);
|
|
2905
|
+
};
|
|
2285
2906
|
};
|
|
2286
2907
|
var notifyPendingListener = (listener, value) => {
|
|
2287
2908
|
if (listener.length > 0) {
|
|
@@ -2311,4 +2932,11 @@ var notifyPlanListener = (listener, value) => {
|
|
|
2311
2932
|
listener();
|
|
2312
2933
|
}
|
|
2313
2934
|
};
|
|
2935
|
+
var notifyCreditBalanceListener = (listener, value) => {
|
|
2936
|
+
if (listener.length > 0) {
|
|
2937
|
+
listener(value);
|
|
2938
|
+
} else {
|
|
2939
|
+
listener();
|
|
2940
|
+
}
|
|
2941
|
+
};
|
|
2314
2942
|
/* @preserve */
|