@schematichq/schematic-js 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/dist/schematic.browser.js +2 -2
- package/dist/schematic.cjs.js +1267 -36
- package/dist/schematic.d.ts +760 -21
- package/dist/schematic.esm.js +1271 -36
- package/package.json +26 -28
package/dist/schematic.esm.js
CHANGED
|
@@ -5,7 +5,15 @@ 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
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
17
|
};
|
|
10
18
|
var __copyProps = (to, from, except, desc) => {
|
|
11
19
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -24,9 +32,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
32
|
mod
|
|
25
33
|
));
|
|
26
34
|
|
|
27
|
-
// node_modules/cross-fetch/dist/browser-polyfill.js
|
|
35
|
+
// node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js
|
|
28
36
|
var require_browser_polyfill = __commonJS({
|
|
29
|
-
"node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
|
|
37
|
+
"node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
|
|
30
38
|
(function(self2) {
|
|
31
39
|
var irrelevant = (function(exports2) {
|
|
32
40
|
var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
|
|
@@ -560,7 +568,7 @@ var require_browser_polyfill = __commonJS({
|
|
|
560
568
|
}
|
|
561
569
|
});
|
|
562
570
|
|
|
563
|
-
// node_modules/uuid/dist/stringify.js
|
|
571
|
+
// node_modules/.pnpm/uuid@14.0.2/node_modules/uuid/dist/stringify.js
|
|
564
572
|
var byteToHex = [];
|
|
565
573
|
for (let i = 0; i < 256; ++i) {
|
|
566
574
|
byteToHex.push((i + 256).toString(16).slice(1));
|
|
@@ -569,24 +577,19 @@ function unsafeStringify(arr, offset = 0) {
|
|
|
569
577
|
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();
|
|
570
578
|
}
|
|
571
579
|
|
|
572
|
-
// node_modules/uuid/dist/rng.js
|
|
573
|
-
var getRandomValues;
|
|
580
|
+
// node_modules/.pnpm/uuid@14.0.2/node_modules/uuid/dist/rng.js
|
|
574
581
|
var rnds8 = new Uint8Array(16);
|
|
575
582
|
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);
|
|
583
|
+
return crypto.getRandomValues(rnds8);
|
|
583
584
|
}
|
|
584
585
|
|
|
585
|
-
// node_modules/uuid/dist/
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
586
|
+
// node_modules/.pnpm/uuid@14.0.2/node_modules/uuid/dist/v4.js
|
|
587
|
+
function v4(options, buf, offset) {
|
|
588
|
+
if (!buf && !options && crypto.randomUUID) {
|
|
589
|
+
return crypto.randomUUID();
|
|
590
|
+
}
|
|
591
|
+
return _v4(options, buf, offset);
|
|
592
|
+
}
|
|
590
593
|
function _v4(options, buf, offset) {
|
|
591
594
|
options = options || {};
|
|
592
595
|
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
@@ -607,12 +610,6 @@ function _v4(options, buf, offset) {
|
|
|
607
610
|
}
|
|
608
611
|
return unsafeStringify(rnds);
|
|
609
612
|
}
|
|
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
613
|
var v4_default = v4;
|
|
617
614
|
|
|
618
615
|
// src/index.ts
|
|
@@ -626,6 +623,36 @@ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
626
623
|
return json;
|
|
627
624
|
}
|
|
628
625
|
|
|
626
|
+
// src/types/api/models/MetricPeriodMonthReset.ts
|
|
627
|
+
function MetricPeriodMonthResetFromJSON(json) {
|
|
628
|
+
return MetricPeriodMonthResetFromJSONTyped(json, false);
|
|
629
|
+
}
|
|
630
|
+
function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
|
|
631
|
+
return json;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/types/api/models/WarningTier.ts
|
|
635
|
+
function WarningTierFromJSON(json) {
|
|
636
|
+
return WarningTierFromJSONTyped(json, false);
|
|
637
|
+
}
|
|
638
|
+
function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
|
|
639
|
+
if (json == null) {
|
|
640
|
+
return json;
|
|
641
|
+
}
|
|
642
|
+
return {
|
|
643
|
+
key: json["key"],
|
|
644
|
+
value: json["value"]
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// src/types/api/models/MetricPeriod.ts
|
|
649
|
+
function MetricPeriodFromJSON(json) {
|
|
650
|
+
return MetricPeriodFromJSONTyped(json, false);
|
|
651
|
+
}
|
|
652
|
+
function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
|
|
653
|
+
return json;
|
|
654
|
+
}
|
|
655
|
+
|
|
629
656
|
// src/types/api/models/FeatureEntitlement.ts
|
|
630
657
|
function FeatureEntitlementFromJSON(json) {
|
|
631
658
|
return FeatureEntitlementFromJSONTyped(json, false);
|
|
@@ -636,22 +663,35 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
636
663
|
}
|
|
637
664
|
return {
|
|
638
665
|
allocation: json["allocation"] == null ? void 0 : json["allocation"],
|
|
666
|
+
consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
|
|
639
667
|
creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
|
|
640
668
|
creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
|
|
669
|
+
creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
|
|
670
|
+
creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
|
|
641
671
|
creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
|
|
642
672
|
creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
|
|
643
673
|
eventName: json["event_name"] == null ? void 0 : json["event_name"],
|
|
674
|
+
eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
|
|
644
675
|
featureId: json["feature_id"],
|
|
645
676
|
featureKey: json["feature_key"],
|
|
646
|
-
metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
|
|
677
|
+
metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
|
|
647
678
|
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"],
|
|
679
|
+
monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
|
|
649
680
|
softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
|
|
650
681
|
usage: json["usage"] == null ? void 0 : json["usage"],
|
|
651
|
-
valueType: EntitlementValueTypeFromJSON(json["value_type"])
|
|
682
|
+
valueType: EntitlementValueTypeFromJSON(json["value_type"]),
|
|
683
|
+
warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
|
|
652
684
|
};
|
|
653
685
|
}
|
|
654
686
|
|
|
687
|
+
// src/types/api/models/RuleType.ts
|
|
688
|
+
function RuleTypeFromJSON(json) {
|
|
689
|
+
return RuleTypeFromJSONTyped(json, false);
|
|
690
|
+
}
|
|
691
|
+
function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
692
|
+
return json;
|
|
693
|
+
}
|
|
694
|
+
|
|
655
695
|
// src/types/api/models/CheckFlagResponseData.ts
|
|
656
696
|
function CheckFlagResponseDataFromJSON(json) {
|
|
657
697
|
return CheckFlagResponseDataFromJSONTyped(json, false);
|
|
@@ -667,13 +707,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
667
707
|
featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
|
|
668
708
|
featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
|
|
669
709
|
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"],
|
|
710
|
+
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
|
|
671
711
|
featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
|
|
672
712
|
flag: json["flag"],
|
|
673
713
|
flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
|
|
674
714
|
reason: json["reason"],
|
|
675
715
|
ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
|
|
676
|
-
ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
|
|
716
|
+
ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
|
|
677
717
|
userId: json["user_id"] == null ? void 0 : json["user_id"],
|
|
678
718
|
value: json["value"]
|
|
679
719
|
};
|
|
@@ -693,6 +733,272 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
693
733
|
};
|
|
694
734
|
}
|
|
695
735
|
|
|
736
|
+
// src/types/api/runtime.ts
|
|
737
|
+
var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
|
|
738
|
+
var Configuration = class {
|
|
739
|
+
constructor(configuration = {}) {
|
|
740
|
+
this.configuration = configuration;
|
|
741
|
+
}
|
|
742
|
+
configuration;
|
|
743
|
+
set config(configuration) {
|
|
744
|
+
this.configuration = configuration;
|
|
745
|
+
}
|
|
746
|
+
get basePath() {
|
|
747
|
+
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
|
748
|
+
}
|
|
749
|
+
get fetchApi() {
|
|
750
|
+
return this.configuration.fetchApi;
|
|
751
|
+
}
|
|
752
|
+
get middleware() {
|
|
753
|
+
return this.configuration.middleware || [];
|
|
754
|
+
}
|
|
755
|
+
get queryParamsStringify() {
|
|
756
|
+
return this.configuration.queryParamsStringify || querystring;
|
|
757
|
+
}
|
|
758
|
+
get username() {
|
|
759
|
+
return this.configuration.username;
|
|
760
|
+
}
|
|
761
|
+
get password() {
|
|
762
|
+
return this.configuration.password;
|
|
763
|
+
}
|
|
764
|
+
get apiKey() {
|
|
765
|
+
const apiKey = this.configuration.apiKey;
|
|
766
|
+
if (apiKey) {
|
|
767
|
+
return typeof apiKey === "function" ? apiKey : () => apiKey;
|
|
768
|
+
}
|
|
769
|
+
return void 0;
|
|
770
|
+
}
|
|
771
|
+
get accessToken() {
|
|
772
|
+
const accessToken = this.configuration.accessToken;
|
|
773
|
+
if (accessToken) {
|
|
774
|
+
return typeof accessToken === "function" ? accessToken : async () => accessToken;
|
|
775
|
+
}
|
|
776
|
+
return void 0;
|
|
777
|
+
}
|
|
778
|
+
get headers() {
|
|
779
|
+
return this.configuration.headers;
|
|
780
|
+
}
|
|
781
|
+
get credentials() {
|
|
782
|
+
return this.configuration.credentials;
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
var DefaultConfig = new Configuration();
|
|
786
|
+
var BaseAPI = class _BaseAPI {
|
|
787
|
+
constructor(configuration = DefaultConfig) {
|
|
788
|
+
this.configuration = configuration;
|
|
789
|
+
this.middleware = configuration.middleware;
|
|
790
|
+
}
|
|
791
|
+
configuration;
|
|
792
|
+
static jsonRegex = new RegExp(
|
|
793
|
+
"^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
|
|
794
|
+
"i"
|
|
795
|
+
);
|
|
796
|
+
middleware;
|
|
797
|
+
withMiddleware(...middlewares) {
|
|
798
|
+
const next = this.clone();
|
|
799
|
+
next.middleware = next.middleware.concat(...middlewares);
|
|
800
|
+
return next;
|
|
801
|
+
}
|
|
802
|
+
withPreMiddleware(...preMiddlewares) {
|
|
803
|
+
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
|
804
|
+
return this.withMiddleware(...middlewares);
|
|
805
|
+
}
|
|
806
|
+
withPostMiddleware(...postMiddlewares) {
|
|
807
|
+
const middlewares = postMiddlewares.map((post) => ({ post }));
|
|
808
|
+
return this.withMiddleware(...middlewares);
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Check if the given MIME is a JSON MIME.
|
|
812
|
+
* JSON MIME examples:
|
|
813
|
+
* application/json
|
|
814
|
+
* application/json; charset=UTF8
|
|
815
|
+
* APPLICATION/JSON
|
|
816
|
+
* application/vnd.company+json
|
|
817
|
+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
|
818
|
+
* @return True if the given MIME is JSON, false otherwise.
|
|
819
|
+
*/
|
|
820
|
+
isJsonMime(mime) {
|
|
821
|
+
if (!mime) {
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
return _BaseAPI.jsonRegex.test(mime);
|
|
825
|
+
}
|
|
826
|
+
async request(context, initOverrides) {
|
|
827
|
+
const { url, init } = await this.createFetchParams(context, initOverrides);
|
|
828
|
+
const response = await this.fetchApi(url, init);
|
|
829
|
+
if (response && response.status >= 200 && response.status < 300) {
|
|
830
|
+
return response;
|
|
831
|
+
}
|
|
832
|
+
throw new ResponseError(response, "Response returned an error code");
|
|
833
|
+
}
|
|
834
|
+
async createFetchParams(context, initOverrides) {
|
|
835
|
+
let url = this.configuration.basePath + context.path;
|
|
836
|
+
if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
|
|
837
|
+
url += "?" + this.configuration.queryParamsStringify(context.query);
|
|
838
|
+
}
|
|
839
|
+
const headers = Object.assign(
|
|
840
|
+
{},
|
|
841
|
+
this.configuration.headers,
|
|
842
|
+
context.headers
|
|
843
|
+
);
|
|
844
|
+
Object.keys(headers).forEach(
|
|
845
|
+
(key) => headers[key] === void 0 ? delete headers[key] : {}
|
|
846
|
+
);
|
|
847
|
+
const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
|
|
848
|
+
const initParams = {
|
|
849
|
+
method: context.method,
|
|
850
|
+
headers,
|
|
851
|
+
body: context.body,
|
|
852
|
+
credentials: this.configuration.credentials
|
|
853
|
+
};
|
|
854
|
+
const overriddenInit = {
|
|
855
|
+
...initParams,
|
|
856
|
+
...await initOverrideFn({
|
|
857
|
+
init: initParams,
|
|
858
|
+
context
|
|
859
|
+
})
|
|
860
|
+
};
|
|
861
|
+
let body;
|
|
862
|
+
if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
|
|
863
|
+
body = overriddenInit.body;
|
|
864
|
+
} else if (this.isJsonMime(headers["Content-Type"])) {
|
|
865
|
+
body = JSON.stringify(overriddenInit.body);
|
|
866
|
+
} else {
|
|
867
|
+
body = overriddenInit.body;
|
|
868
|
+
}
|
|
869
|
+
const init = {
|
|
870
|
+
...overriddenInit,
|
|
871
|
+
body
|
|
872
|
+
};
|
|
873
|
+
return { url, init };
|
|
874
|
+
}
|
|
875
|
+
fetchApi = async (url, init) => {
|
|
876
|
+
let fetchParams = { url, init };
|
|
877
|
+
for (const middleware of this.middleware) {
|
|
878
|
+
if (middleware.pre) {
|
|
879
|
+
fetchParams = await middleware.pre({
|
|
880
|
+
fetch: this.fetchApi,
|
|
881
|
+
...fetchParams
|
|
882
|
+
}) || fetchParams;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
let response = void 0;
|
|
886
|
+
try {
|
|
887
|
+
response = await (this.configuration.fetchApi || fetch)(
|
|
888
|
+
fetchParams.url,
|
|
889
|
+
fetchParams.init
|
|
890
|
+
);
|
|
891
|
+
} catch (e) {
|
|
892
|
+
for (const middleware of this.middleware) {
|
|
893
|
+
if (middleware.onError) {
|
|
894
|
+
response = await middleware.onError({
|
|
895
|
+
fetch: this.fetchApi,
|
|
896
|
+
url: fetchParams.url,
|
|
897
|
+
init: fetchParams.init,
|
|
898
|
+
error: e,
|
|
899
|
+
response: response ? response.clone() : void 0
|
|
900
|
+
}) || response;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
if (response === void 0) {
|
|
904
|
+
if (e instanceof Error) {
|
|
905
|
+
throw new FetchError(
|
|
906
|
+
e,
|
|
907
|
+
"The request failed and the interceptors did not return an alternative response"
|
|
908
|
+
);
|
|
909
|
+
} else {
|
|
910
|
+
throw e;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
for (const middleware of this.middleware) {
|
|
915
|
+
if (middleware.post) {
|
|
916
|
+
response = await middleware.post({
|
|
917
|
+
fetch: this.fetchApi,
|
|
918
|
+
url: fetchParams.url,
|
|
919
|
+
init: fetchParams.init,
|
|
920
|
+
response: response.clone()
|
|
921
|
+
}) || response;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return response;
|
|
925
|
+
};
|
|
926
|
+
/**
|
|
927
|
+
* Create a shallow clone of `this` by constructing a new instance
|
|
928
|
+
* and then shallow cloning data members.
|
|
929
|
+
*/
|
|
930
|
+
clone() {
|
|
931
|
+
const constructor = this.constructor;
|
|
932
|
+
const next = new constructor(this.configuration);
|
|
933
|
+
next.middleware = this.middleware.slice();
|
|
934
|
+
return next;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
function isBlob(value) {
|
|
938
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
939
|
+
}
|
|
940
|
+
function isFormData(value) {
|
|
941
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
942
|
+
}
|
|
943
|
+
var ResponseError = class extends Error {
|
|
944
|
+
constructor(response, msg) {
|
|
945
|
+
super(msg);
|
|
946
|
+
this.response = response;
|
|
947
|
+
}
|
|
948
|
+
response;
|
|
949
|
+
name = "ResponseError";
|
|
950
|
+
};
|
|
951
|
+
var FetchError = class extends Error {
|
|
952
|
+
constructor(cause, msg) {
|
|
953
|
+
super(msg);
|
|
954
|
+
this.cause = cause;
|
|
955
|
+
}
|
|
956
|
+
cause;
|
|
957
|
+
name = "FetchError";
|
|
958
|
+
};
|
|
959
|
+
function querystring(params, prefix = "") {
|
|
960
|
+
return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
|
|
961
|
+
}
|
|
962
|
+
function querystringSingleKey(key, value, keyPrefix = "") {
|
|
963
|
+
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
|
964
|
+
if (value instanceof Array) {
|
|
965
|
+
const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
|
|
966
|
+
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
|
967
|
+
}
|
|
968
|
+
if (value instanceof Set) {
|
|
969
|
+
const valueAsArray = Array.from(value);
|
|
970
|
+
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
|
971
|
+
}
|
|
972
|
+
if (value instanceof Date) {
|
|
973
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
|
974
|
+
}
|
|
975
|
+
if (value instanceof Object) {
|
|
976
|
+
return querystring(value, fullKey);
|
|
977
|
+
}
|
|
978
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
|
979
|
+
}
|
|
980
|
+
function mapValues(data, fn) {
|
|
981
|
+
return Object.keys(data).reduce(
|
|
982
|
+
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
|
983
|
+
{}
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/types/api/models/CompanyCreditBalance.ts
|
|
988
|
+
function CompanyCreditBalanceFromJSON(json) {
|
|
989
|
+
return CompanyCreditBalanceFromJSONTyped(json, false);
|
|
990
|
+
}
|
|
991
|
+
function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
|
|
992
|
+
if (json == null) {
|
|
993
|
+
return json;
|
|
994
|
+
}
|
|
995
|
+
return {
|
|
996
|
+
remaining: json["remaining"],
|
|
997
|
+
reserved: json["reserved"],
|
|
998
|
+
settled: json["settled"]
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
696
1002
|
// src/types/api/models/TrialStatus.ts
|
|
697
1003
|
var TrialStatus = {
|
|
698
1004
|
Active: "active",
|
|
@@ -731,6 +1037,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
731
1037
|
return json;
|
|
732
1038
|
}
|
|
733
1039
|
return {
|
|
1040
|
+
creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
|
|
734
1041
|
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
735
1042
|
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
736
1043
|
};
|
|
@@ -763,6 +1070,7 @@ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
|
763
1070
|
error: value["error"],
|
|
764
1071
|
flag_id: value["flagId"],
|
|
765
1072
|
flag_key: value["flagKey"],
|
|
1073
|
+
preflight: value["preflight"],
|
|
766
1074
|
reason: value["reason"],
|
|
767
1075
|
req_company: value["reqCompany"],
|
|
768
1076
|
req_user: value["reqUser"],
|
|
@@ -819,7 +1127,10 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
819
1127
|
return {
|
|
820
1128
|
featureUsageExceeded,
|
|
821
1129
|
companyId: companyId == null ? void 0 : companyId,
|
|
1130
|
+
creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
|
|
822
1131
|
creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
|
|
1132
|
+
creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
|
|
1133
|
+
creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
|
|
823
1134
|
error: error == null ? void 0 : error,
|
|
824
1135
|
featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
|
|
825
1136
|
featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
|
|
@@ -845,6 +1156,24 @@ var CheckPlanReturnFromJSON = (json) => {
|
|
|
845
1156
|
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
846
1157
|
};
|
|
847
1158
|
};
|
|
1159
|
+
var CreditBalancesFromJSON = (json) => {
|
|
1160
|
+
if (json == null || typeof json !== "object") {
|
|
1161
|
+
return {};
|
|
1162
|
+
}
|
|
1163
|
+
const balances = {};
|
|
1164
|
+
for (const [creditId, raw] of Object.entries(json)) {
|
|
1165
|
+
if (raw == null || typeof raw !== "object") continue;
|
|
1166
|
+
const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
|
|
1167
|
+
if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
|
|
1168
|
+
continue;
|
|
1169
|
+
}
|
|
1170
|
+
balances[creditId] = { remaining, reserved, settled };
|
|
1171
|
+
}
|
|
1172
|
+
return balances;
|
|
1173
|
+
};
|
|
1174
|
+
|
|
1175
|
+
// src/cacheVersion.ts
|
|
1176
|
+
var cacheVersion = "bb56e75d";
|
|
848
1177
|
|
|
849
1178
|
// src/utils.ts
|
|
850
1179
|
function contextString(context) {
|
|
@@ -863,10 +1192,597 @@ function contextString(context) {
|
|
|
863
1192
|
}
|
|
864
1193
|
|
|
865
1194
|
// src/version.ts
|
|
866
|
-
var version = "1.
|
|
1195
|
+
var version = "1.6.0";
|
|
1196
|
+
|
|
1197
|
+
// src/billing/api/generated/models/index.ts
|
|
1198
|
+
var models_exports = {};
|
|
1199
|
+
__export(models_exports, {
|
|
1200
|
+
ApiErrorFromJSON: () => ApiErrorFromJSON,
|
|
1201
|
+
ApiErrorFromJSONTyped: () => ApiErrorFromJSONTyped,
|
|
1202
|
+
ApiErrorToJSON: () => ApiErrorToJSON,
|
|
1203
|
+
ApiErrorToJSONTyped: () => ApiErrorToJSONTyped,
|
|
1204
|
+
CompanyInvoiceResponseDataFromJSON: () => CompanyInvoiceResponseDataFromJSON,
|
|
1205
|
+
CompanyInvoiceResponseDataFromJSONTyped: () => CompanyInvoiceResponseDataFromJSONTyped,
|
|
1206
|
+
CompanyInvoiceResponseDataToJSON: () => CompanyInvoiceResponseDataToJSON,
|
|
1207
|
+
CompanyInvoiceResponseDataToJSONTyped: () => CompanyInvoiceResponseDataToJSONTyped,
|
|
1208
|
+
CompanyInvoicesResponseDataFromJSON: () => CompanyInvoicesResponseDataFromJSON,
|
|
1209
|
+
CompanyInvoicesResponseDataFromJSONTyped: () => CompanyInvoicesResponseDataFromJSONTyped,
|
|
1210
|
+
CompanyInvoicesResponseDataToJSON: () => CompanyInvoicesResponseDataToJSON,
|
|
1211
|
+
CompanyInvoicesResponseDataToJSONTyped: () => CompanyInvoicesResponseDataToJSONTyped,
|
|
1212
|
+
GetCompanyInvoicesParamsFromJSON: () => GetCompanyInvoicesParamsFromJSON,
|
|
1213
|
+
GetCompanyInvoicesParamsFromJSONTyped: () => GetCompanyInvoicesParamsFromJSONTyped,
|
|
1214
|
+
GetCompanyInvoicesParamsToJSON: () => GetCompanyInvoicesParamsToJSON,
|
|
1215
|
+
GetCompanyInvoicesParamsToJSONTyped: () => GetCompanyInvoicesParamsToJSONTyped,
|
|
1216
|
+
GetCompanyInvoicesResponseFromJSON: () => GetCompanyInvoicesResponseFromJSON,
|
|
1217
|
+
GetCompanyInvoicesResponseFromJSONTyped: () => GetCompanyInvoicesResponseFromJSONTyped,
|
|
1218
|
+
GetCompanyInvoicesResponseToJSON: () => GetCompanyInvoicesResponseToJSON,
|
|
1219
|
+
GetCompanyInvoicesResponseToJSONTyped: () => GetCompanyInvoicesResponseToJSONTyped,
|
|
1220
|
+
InvoiceStatus: () => InvoiceStatus,
|
|
1221
|
+
InvoiceStatusFromJSON: () => InvoiceStatusFromJSON,
|
|
1222
|
+
InvoiceStatusFromJSONTyped: () => InvoiceStatusFromJSONTyped,
|
|
1223
|
+
InvoiceStatusToJSON: () => InvoiceStatusToJSON,
|
|
1224
|
+
InvoiceStatusToJSONTyped: () => InvoiceStatusToJSONTyped,
|
|
1225
|
+
instanceOfApiError: () => instanceOfApiError,
|
|
1226
|
+
instanceOfCompanyInvoiceResponseData: () => instanceOfCompanyInvoiceResponseData,
|
|
1227
|
+
instanceOfCompanyInvoicesResponseData: () => instanceOfCompanyInvoicesResponseData,
|
|
1228
|
+
instanceOfGetCompanyInvoicesParams: () => instanceOfGetCompanyInvoicesParams,
|
|
1229
|
+
instanceOfGetCompanyInvoicesResponse: () => instanceOfGetCompanyInvoicesResponse,
|
|
1230
|
+
instanceOfInvoiceStatus: () => instanceOfInvoiceStatus
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
// src/billing/api/generated/models/ApiError.ts
|
|
1234
|
+
function instanceOfApiError(value) {
|
|
1235
|
+
if (!("error" in value) || value["error"] === void 0) return false;
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
function ApiErrorFromJSON(json) {
|
|
1239
|
+
return ApiErrorFromJSONTyped(json, false);
|
|
1240
|
+
}
|
|
1241
|
+
function ApiErrorFromJSONTyped(json, ignoreDiscriminator) {
|
|
1242
|
+
if (json == null) {
|
|
1243
|
+
return json;
|
|
1244
|
+
}
|
|
1245
|
+
return {
|
|
1246
|
+
error: json["error"]
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
function ApiErrorToJSON(json) {
|
|
1250
|
+
return ApiErrorToJSONTyped(json, false);
|
|
1251
|
+
}
|
|
1252
|
+
function ApiErrorToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1253
|
+
if (value == null) {
|
|
1254
|
+
return value;
|
|
1255
|
+
}
|
|
1256
|
+
return {
|
|
1257
|
+
error: value["error"]
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/billing/api/generated/models/InvoiceStatus.ts
|
|
1262
|
+
var InvoiceStatus = {
|
|
1263
|
+
Draft: "draft",
|
|
1264
|
+
Open: "open",
|
|
1265
|
+
Paid: "paid",
|
|
1266
|
+
Uncollectible: "uncollectible",
|
|
1267
|
+
Void: "void"
|
|
1268
|
+
};
|
|
1269
|
+
function instanceOfInvoiceStatus(value) {
|
|
1270
|
+
for (const key in InvoiceStatus) {
|
|
1271
|
+
if (Object.prototype.hasOwnProperty.call(InvoiceStatus, key)) {
|
|
1272
|
+
if (InvoiceStatus[key] === value) {
|
|
1273
|
+
return true;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
function InvoiceStatusFromJSON(json) {
|
|
1280
|
+
return InvoiceStatusFromJSONTyped(json, false);
|
|
1281
|
+
}
|
|
1282
|
+
function InvoiceStatusFromJSONTyped(json, ignoreDiscriminator) {
|
|
1283
|
+
return json;
|
|
1284
|
+
}
|
|
1285
|
+
function InvoiceStatusToJSON(value) {
|
|
1286
|
+
return value;
|
|
1287
|
+
}
|
|
1288
|
+
function InvoiceStatusToJSONTyped(value, ignoreDiscriminator) {
|
|
1289
|
+
return value;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// src/billing/api/generated/models/CompanyInvoiceResponseData.ts
|
|
1293
|
+
function instanceOfCompanyInvoiceResponseData(value) {
|
|
1294
|
+
if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
|
|
1295
|
+
if (!("createdAt" in value) || value["createdAt"] === void 0) return false;
|
|
1296
|
+
if (!("currency" in value) || value["currency"] === void 0) return false;
|
|
1297
|
+
if (!("id" in value) || value["id"] === void 0) return false;
|
|
1298
|
+
return true;
|
|
1299
|
+
}
|
|
1300
|
+
function CompanyInvoiceResponseDataFromJSON(json) {
|
|
1301
|
+
return CompanyInvoiceResponseDataFromJSONTyped(json, false);
|
|
1302
|
+
}
|
|
1303
|
+
function CompanyInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
1304
|
+
if (json == null) {
|
|
1305
|
+
return json;
|
|
1306
|
+
}
|
|
1307
|
+
return {
|
|
1308
|
+
amountDue: json["amount_due"],
|
|
1309
|
+
createdAt: new Date(json["created_at"]),
|
|
1310
|
+
currency: json["currency"],
|
|
1311
|
+
dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
|
|
1312
|
+
id: json["id"],
|
|
1313
|
+
status: json["status"] == null ? void 0 : InvoiceStatusFromJSON(json["status"]),
|
|
1314
|
+
url: json["url"] == null ? void 0 : json["url"]
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
function CompanyInvoiceResponseDataToJSON(json) {
|
|
1318
|
+
return CompanyInvoiceResponseDataToJSONTyped(json, false);
|
|
1319
|
+
}
|
|
1320
|
+
function CompanyInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1321
|
+
if (value == null) {
|
|
1322
|
+
return value;
|
|
1323
|
+
}
|
|
1324
|
+
return {
|
|
1325
|
+
amount_due: value["amountDue"],
|
|
1326
|
+
created_at: value["createdAt"].toISOString(),
|
|
1327
|
+
currency: value["currency"],
|
|
1328
|
+
due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
|
|
1329
|
+
id: value["id"],
|
|
1330
|
+
status: InvoiceStatusToJSON(value["status"]),
|
|
1331
|
+
url: value["url"]
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// src/billing/api/generated/models/CompanyInvoicesResponseData.ts
|
|
1336
|
+
function instanceOfCompanyInvoicesResponseData(value) {
|
|
1337
|
+
if (!("count" in value) || value["count"] === void 0) return false;
|
|
1338
|
+
if (!("invoices" in value) || value["invoices"] === void 0) return false;
|
|
1339
|
+
return true;
|
|
1340
|
+
}
|
|
1341
|
+
function CompanyInvoicesResponseDataFromJSON(json) {
|
|
1342
|
+
return CompanyInvoicesResponseDataFromJSONTyped(json, false);
|
|
1343
|
+
}
|
|
1344
|
+
function CompanyInvoicesResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
1345
|
+
if (json == null) {
|
|
1346
|
+
return json;
|
|
1347
|
+
}
|
|
1348
|
+
return {
|
|
1349
|
+
count: json["count"],
|
|
1350
|
+
invoices: json["invoices"].map(
|
|
1351
|
+
CompanyInvoiceResponseDataFromJSON
|
|
1352
|
+
)
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
function CompanyInvoicesResponseDataToJSON(json) {
|
|
1356
|
+
return CompanyInvoicesResponseDataToJSONTyped(json, false);
|
|
1357
|
+
}
|
|
1358
|
+
function CompanyInvoicesResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1359
|
+
if (value == null) {
|
|
1360
|
+
return value;
|
|
1361
|
+
}
|
|
1362
|
+
return {
|
|
1363
|
+
count: value["count"],
|
|
1364
|
+
invoices: value["invoices"].map(
|
|
1365
|
+
CompanyInvoiceResponseDataToJSON
|
|
1366
|
+
)
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// src/billing/api/generated/models/GetCompanyInvoicesParams.ts
|
|
1371
|
+
function instanceOfGetCompanyInvoicesParams(value) {
|
|
1372
|
+
return true;
|
|
1373
|
+
}
|
|
1374
|
+
function GetCompanyInvoicesParamsFromJSON(json) {
|
|
1375
|
+
return GetCompanyInvoicesParamsFromJSONTyped(json, false);
|
|
1376
|
+
}
|
|
1377
|
+
function GetCompanyInvoicesParamsFromJSONTyped(json, ignoreDiscriminator) {
|
|
1378
|
+
if (json == null) {
|
|
1379
|
+
return json;
|
|
1380
|
+
}
|
|
1381
|
+
return {
|
|
1382
|
+
includePending: json["include_pending"] == null ? void 0 : json["include_pending"],
|
|
1383
|
+
limit: json["limit"] == null ? void 0 : json["limit"],
|
|
1384
|
+
offset: json["offset"] == null ? void 0 : json["offset"]
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
function GetCompanyInvoicesParamsToJSON(json) {
|
|
1388
|
+
return GetCompanyInvoicesParamsToJSONTyped(json, false);
|
|
1389
|
+
}
|
|
1390
|
+
function GetCompanyInvoicesParamsToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1391
|
+
if (value == null) {
|
|
1392
|
+
return value;
|
|
1393
|
+
}
|
|
1394
|
+
return {
|
|
1395
|
+
include_pending: value["includePending"],
|
|
1396
|
+
limit: value["limit"],
|
|
1397
|
+
offset: value["offset"]
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// src/billing/api/generated/models/GetCompanyInvoicesResponse.ts
|
|
1402
|
+
function instanceOfGetCompanyInvoicesResponse(value) {
|
|
1403
|
+
if (!("data" in value) || value["data"] === void 0) return false;
|
|
1404
|
+
if (!("params" in value) || value["params"] === void 0) return false;
|
|
1405
|
+
return true;
|
|
1406
|
+
}
|
|
1407
|
+
function GetCompanyInvoicesResponseFromJSON(json) {
|
|
1408
|
+
return GetCompanyInvoicesResponseFromJSONTyped(json, false);
|
|
1409
|
+
}
|
|
1410
|
+
function GetCompanyInvoicesResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
1411
|
+
if (json == null) {
|
|
1412
|
+
return json;
|
|
1413
|
+
}
|
|
1414
|
+
return {
|
|
1415
|
+
data: CompanyInvoicesResponseDataFromJSON(json["data"]),
|
|
1416
|
+
params: GetCompanyInvoicesParamsFromJSON(json["params"])
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
function GetCompanyInvoicesResponseToJSON(json) {
|
|
1420
|
+
return GetCompanyInvoicesResponseToJSONTyped(json, false);
|
|
1421
|
+
}
|
|
1422
|
+
function GetCompanyInvoicesResponseToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1423
|
+
if (value == null) {
|
|
1424
|
+
return value;
|
|
1425
|
+
}
|
|
1426
|
+
return {
|
|
1427
|
+
data: CompanyInvoicesResponseDataToJSON(value["data"]),
|
|
1428
|
+
params: GetCompanyInvoicesParamsToJSON(value["params"])
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// src/billing/contract/invoices.ts
|
|
1433
|
+
var DEFAULT_INVOICE_QUERY = {};
|
|
1434
|
+
function normalizeInvoiceQuery(query) {
|
|
1435
|
+
const { includePending, ...rest } = query;
|
|
1436
|
+
return includePending === true ? { ...rest, includePending: true } : rest;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// src/billing/session.ts
|
|
1440
|
+
var SchematicApiError = class extends Error {
|
|
1441
|
+
constructor(status, path, body) {
|
|
1442
|
+
super(
|
|
1443
|
+
typeof body === "object" && body !== null && "error" in body ? String(body.error) : `Request to ${path} failed with status ${status}`
|
|
1444
|
+
);
|
|
1445
|
+
this.status = status;
|
|
1446
|
+
this.path = path;
|
|
1447
|
+
this.body = body;
|
|
1448
|
+
this.name = "SchematicApiError";
|
|
1449
|
+
}
|
|
1450
|
+
status;
|
|
1451
|
+
path;
|
|
1452
|
+
body;
|
|
1453
|
+
};
|
|
1454
|
+
var DEFAULT_API_URL = "https://api.schematichq.com";
|
|
1455
|
+
var TOKEN_CACHE_SIZE = 10;
|
|
1456
|
+
function sessionKey(session) {
|
|
1457
|
+
return JSON.stringify([session.company, session.user ?? null]);
|
|
1458
|
+
}
|
|
1459
|
+
var SchematicSession = class {
|
|
1460
|
+
_apiUrl;
|
|
1461
|
+
_headers;
|
|
1462
|
+
_fetch;
|
|
1463
|
+
_session;
|
|
1464
|
+
_tokens = /* @__PURE__ */ new Map();
|
|
1465
|
+
_resolving = /* @__PURE__ */ new Map();
|
|
1466
|
+
/**
|
|
1467
|
+
* Bumped when the session's identity changes, and only then — the object
|
|
1468
|
+
* itself is replaced on every render. Anything asking "is this still the
|
|
1469
|
+
* session I started under?" counts generations rather than comparing.
|
|
1470
|
+
*/
|
|
1471
|
+
_generation = 0;
|
|
1472
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
1473
|
+
constructor(options = {}) {
|
|
1474
|
+
this._session = options.session;
|
|
1475
|
+
this._apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
1476
|
+
this._headers = options.additionalHeaders ?? {};
|
|
1477
|
+
this._fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
1478
|
+
}
|
|
1479
|
+
get key() {
|
|
1480
|
+
return this._session === null || this._session === void 0 ? void 0 : sessionKey(this._session);
|
|
1481
|
+
}
|
|
1482
|
+
get status() {
|
|
1483
|
+
if (this._session === void 0) {
|
|
1484
|
+
return "pending";
|
|
1485
|
+
}
|
|
1486
|
+
return this._session === null ? "ended" : "active";
|
|
1487
|
+
}
|
|
1488
|
+
/** Only a statement that changes which pair is read counts as a change. */
|
|
1489
|
+
set(session) {
|
|
1490
|
+
if (session === void 0) {
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
const previous = this._session;
|
|
1494
|
+
this._session = session;
|
|
1495
|
+
if (session === null) {
|
|
1496
|
+
if (previous === null) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
this._tokens.clear();
|
|
1500
|
+
this._resolving.clear();
|
|
1501
|
+
this._generation += 1;
|
|
1502
|
+
this._emit({ type: "ended" });
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
if (previous !== null && previous !== void 0) {
|
|
1506
|
+
if (previous.company === session.company && (previous.user ?? null) === (session.user ?? null)) {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
this._generation += 1;
|
|
1510
|
+
this._emit({ type: "changed" });
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
this._generation += 1;
|
|
1514
|
+
this._emit({ type: "started" });
|
|
1515
|
+
}
|
|
1516
|
+
onChange(listener) {
|
|
1517
|
+
this._listeners.add(listener);
|
|
1518
|
+
return () => {
|
|
1519
|
+
this._listeners.delete(listener);
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
_emit(event) {
|
|
1523
|
+
for (const listener of this._listeners) {
|
|
1524
|
+
listener(event);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
_cached(key) {
|
|
1528
|
+
const cached = this._tokens.get(key);
|
|
1529
|
+
if (cached === void 0) {
|
|
1530
|
+
return void 0;
|
|
1531
|
+
}
|
|
1532
|
+
if (cached.expiresAt !== void 0 && cached.expiresAt.getTime() <= Date.now()) {
|
|
1533
|
+
this._tokens.delete(key);
|
|
1534
|
+
return void 0;
|
|
1535
|
+
}
|
|
1536
|
+
this._tokens.delete(key);
|
|
1537
|
+
this._tokens.set(key, cached);
|
|
1538
|
+
return cached;
|
|
1539
|
+
}
|
|
1540
|
+
_cache(key, resolved) {
|
|
1541
|
+
this._tokens.delete(key);
|
|
1542
|
+
this._tokens.set(key, resolved);
|
|
1543
|
+
while (this._tokens.size > TOKEN_CACHE_SIZE) {
|
|
1544
|
+
const oldest = this._tokens.keys().next();
|
|
1545
|
+
if (oldest.done === true) {
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
this._tokens.delete(oldest.value);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* The credential for a session, minted if this one is not held. `force`
|
|
1553
|
+
* retires what is held first: the caller is a request the API has just
|
|
1554
|
+
* rejected.
|
|
1555
|
+
*/
|
|
1556
|
+
resolveToken(session, force) {
|
|
1557
|
+
const { token } = session;
|
|
1558
|
+
if (typeof token === "string") {
|
|
1559
|
+
return Promise.resolve(token);
|
|
1560
|
+
}
|
|
1561
|
+
const key = sessionKey(session);
|
|
1562
|
+
if (!force) {
|
|
1563
|
+
const cached = this._cached(key);
|
|
1564
|
+
if (cached !== void 0) {
|
|
1565
|
+
return Promise.resolve(cached.token);
|
|
1566
|
+
}
|
|
1567
|
+
} else {
|
|
1568
|
+
this._tokens.delete(key);
|
|
1569
|
+
}
|
|
1570
|
+
const inflight = this._resolving.get(key);
|
|
1571
|
+
if (inflight !== void 0 && inflight.sessionGeneration === this._generation && (!force || inflight.forced)) {
|
|
1572
|
+
return inflight.promise;
|
|
1573
|
+
}
|
|
1574
|
+
const provider = token;
|
|
1575
|
+
const sessionGeneration = this._generation;
|
|
1576
|
+
const owns = () => this._resolving.get(key)?.promise === promise;
|
|
1577
|
+
const promise = Promise.resolve().then(() => provider()).then((result) => {
|
|
1578
|
+
const { resolved, stamped } = asResolvedToken(result, session);
|
|
1579
|
+
if (owns() && (this._generation === sessionGeneration || stamped)) {
|
|
1580
|
+
this._cache(key, resolved);
|
|
1581
|
+
}
|
|
1582
|
+
return resolved.token;
|
|
1583
|
+
}).finally(() => {
|
|
1584
|
+
if (owns()) {
|
|
1585
|
+
this._resolving.delete(key);
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
this._resolving.set(key, { promise, forced: force, sessionGeneration });
|
|
1589
|
+
return promise;
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Sends a request under the active session's credential, refreshing once
|
|
1593
|
+
* and retrying if the API rejects it. Rejects rather than answering when
|
|
1594
|
+
* the session changes while the request is in flight: the rows would
|
|
1595
|
+
* otherwise come back as the answer to a question asked for another pair.
|
|
1596
|
+
*/
|
|
1597
|
+
async request(path, options = {}) {
|
|
1598
|
+
const { method = "GET", body } = options;
|
|
1599
|
+
const send = async (credential2) => this._fetch(`${this._apiUrl}${path}`, {
|
|
1600
|
+
method,
|
|
1601
|
+
headers: {
|
|
1602
|
+
"Accept": "application/json",
|
|
1603
|
+
...body === void 0 ? {} : { "Content-Type": "application/json" },
|
|
1604
|
+
...this._headers,
|
|
1605
|
+
"X-Schematic-Api-Key": credential2
|
|
1606
|
+
},
|
|
1607
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) }
|
|
1608
|
+
});
|
|
1609
|
+
const session = this._session;
|
|
1610
|
+
if (session === null) {
|
|
1611
|
+
throw new Error("There is no session to read data for.");
|
|
1612
|
+
}
|
|
1613
|
+
if (session === void 0) {
|
|
1614
|
+
throw new Error("A session is required to read data.");
|
|
1615
|
+
}
|
|
1616
|
+
const provider = session.token;
|
|
1617
|
+
const generation = this._generation;
|
|
1618
|
+
const stillOurs = async (response2) => {
|
|
1619
|
+
if (this._generation === generation) {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
if (response2 !== void 0) {
|
|
1623
|
+
await discardBody(response2);
|
|
1624
|
+
}
|
|
1625
|
+
throw new Error("The session changed while this request was in flight.");
|
|
1626
|
+
};
|
|
1627
|
+
const credential = await this.resolveToken(session, false);
|
|
1628
|
+
if (this._generation !== generation) {
|
|
1629
|
+
throw new Error("The session changed before this request was sent.");
|
|
1630
|
+
}
|
|
1631
|
+
let response = await send(credential);
|
|
1632
|
+
await stillOurs(response);
|
|
1633
|
+
if (response.status === 401 && typeof provider === "function" && this._generation === generation) {
|
|
1634
|
+
const status = response.status;
|
|
1635
|
+
const rejected = await readBody(response);
|
|
1636
|
+
let retried = false;
|
|
1637
|
+
const current = this._session;
|
|
1638
|
+
if (this._generation === generation && current !== null && current !== void 0) {
|
|
1639
|
+
const refreshed = await this.resolveToken(current, true);
|
|
1640
|
+
if (this._generation === generation) {
|
|
1641
|
+
response = await send(refreshed);
|
|
1642
|
+
await stillOurs(response);
|
|
1643
|
+
retried = true;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
if (!retried) {
|
|
1647
|
+
throw new SchematicApiError(status, path, rejected);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
const parsed = await readBody(response);
|
|
1651
|
+
await stillOurs();
|
|
1652
|
+
if (!response.ok) {
|
|
1653
|
+
throw new SchematicApiError(response.status, path, parsed);
|
|
1654
|
+
}
|
|
1655
|
+
return parsed;
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
function asResolvedToken(result, session) {
|
|
1659
|
+
if (typeof result === "string") {
|
|
1660
|
+
return { resolved: { token: result }, stamped: false };
|
|
1661
|
+
}
|
|
1662
|
+
const token = result?.token;
|
|
1663
|
+
if (typeof token !== "string" || token === "") {
|
|
1664
|
+
throw new Error("The access token provider did not return a token.");
|
|
1665
|
+
}
|
|
1666
|
+
if (result.company !== void 0 && result.company !== session.company || result.user !== void 0 && session.user !== void 0 && result.user !== session.user) {
|
|
1667
|
+
throw new Error(
|
|
1668
|
+
"The access token provider returned a token for a different session."
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
const stamped = result.company !== void 0 && (session.user === void 0 || result.user !== void 0);
|
|
1672
|
+
return { resolved: { token, expiresAt: asDate(result.expiresAt) }, stamped };
|
|
1673
|
+
}
|
|
1674
|
+
function asDate(value) {
|
|
1675
|
+
if (value === void 0 || value === null) {
|
|
1676
|
+
return void 0;
|
|
1677
|
+
}
|
|
1678
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
1679
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1680
|
+
}
|
|
1681
|
+
async function discardBody(response) {
|
|
1682
|
+
try {
|
|
1683
|
+
await response.body?.cancel();
|
|
1684
|
+
} catch {
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
async function readBody(response) {
|
|
1688
|
+
const text = await response.text();
|
|
1689
|
+
if (text === "") {
|
|
1690
|
+
return null;
|
|
1691
|
+
}
|
|
1692
|
+
try {
|
|
1693
|
+
return JSON.parse(text);
|
|
1694
|
+
} catch {
|
|
1695
|
+
return text;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// src/billing/client.ts
|
|
1700
|
+
var INVOICE_PAGE_SIZE = 12;
|
|
1701
|
+
var INVOICE_MAX_PAGE_SIZE = 250;
|
|
1702
|
+
var SchematicBillingClient = class {
|
|
1703
|
+
/**
|
|
1704
|
+
* Public so a second client over the same surface can be constructed on
|
|
1705
|
+
* this one rather than minting tokens of its own.
|
|
1706
|
+
*/
|
|
1707
|
+
session;
|
|
1708
|
+
constructor(options = {}) {
|
|
1709
|
+
this.session = options instanceof SchematicSession ? options : new SchematicSession(options);
|
|
1710
|
+
}
|
|
1711
|
+
get sessionKey() {
|
|
1712
|
+
return this.session.key;
|
|
1713
|
+
}
|
|
1714
|
+
get sessionStatus() {
|
|
1715
|
+
return this.session.status;
|
|
1716
|
+
}
|
|
1717
|
+
setSession(session) {
|
|
1718
|
+
this.session.set(session);
|
|
1719
|
+
}
|
|
1720
|
+
onSessionChange(listener) {
|
|
1721
|
+
return this.session.onChange(listener);
|
|
1722
|
+
}
|
|
1723
|
+
fetchInvoices(params) {
|
|
1724
|
+
const query = new URLSearchParams({
|
|
1725
|
+
limit: String(Math.min(params.limit, INVOICE_MAX_PAGE_SIZE)),
|
|
1726
|
+
offset: String(params.offset)
|
|
1727
|
+
});
|
|
1728
|
+
if (params.includePending !== void 0) {
|
|
1729
|
+
query.set("include_pending", String(params.includePending));
|
|
1730
|
+
}
|
|
1731
|
+
const path = `/company/invoices?${query}`;
|
|
1732
|
+
return this.session.request(path).then((body) => {
|
|
1733
|
+
if (body === null || typeof body !== "object" || !("data" in body)) {
|
|
1734
|
+
throw new Error(`Malformed response from ${path}`);
|
|
1735
|
+
}
|
|
1736
|
+
const data = body.data;
|
|
1737
|
+
if (data == null || data.invoices == null) {
|
|
1738
|
+
return { invoices: [], count: 0 };
|
|
1739
|
+
}
|
|
1740
|
+
const decoded = GetCompanyInvoicesResponseFromJSON(body).data;
|
|
1741
|
+
return { invoices: decoded.invoices, count: decoded.count };
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
};
|
|
1745
|
+
async function fetchBillingData(client, options = {}) {
|
|
1746
|
+
const wanted = options.names ?? ["invoices"];
|
|
1747
|
+
const data = {};
|
|
1748
|
+
const invoices = options.invoices === void 0 ? void 0 : normalizeInvoiceQuery(options.invoices);
|
|
1749
|
+
if (invoices !== void 0) {
|
|
1750
|
+
data.params = { invoices };
|
|
1751
|
+
}
|
|
1752
|
+
data.sessionKey = client.sessionKey;
|
|
1753
|
+
await Promise.all(
|
|
1754
|
+
wanted.map(async (name) => {
|
|
1755
|
+
try {
|
|
1756
|
+
switch (name) {
|
|
1757
|
+
case "invoices": {
|
|
1758
|
+
const page = await client.fetchInvoices({
|
|
1759
|
+
...invoices ?? {},
|
|
1760
|
+
limit: INVOICE_PAGE_SIZE,
|
|
1761
|
+
offset: 0
|
|
1762
|
+
});
|
|
1763
|
+
data.invoices = {
|
|
1764
|
+
invoices: page.invoices,
|
|
1765
|
+
count: page.count,
|
|
1766
|
+
// Two queries on the server: a count that outran the rows
|
|
1767
|
+
// would seed a page that pages nothing.
|
|
1768
|
+
hasMore: page.invoices.length > 0 && page.invoices.length < page.count
|
|
1769
|
+
};
|
|
1770
|
+
break;
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
} catch {
|
|
1774
|
+
}
|
|
1775
|
+
})
|
|
1776
|
+
);
|
|
1777
|
+
return data;
|
|
1778
|
+
}
|
|
867
1779
|
|
|
868
1780
|
// src/index.ts
|
|
869
1781
|
var anonymousIdKey = "schematicId";
|
|
1782
|
+
var flagStateCachePrefix = "schematicCache";
|
|
1783
|
+
var flagStateCacheMaxContexts = 10;
|
|
1784
|
+
var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1785
|
+
var emptyCreditBalances = Object.freeze({});
|
|
870
1786
|
var Schematic = class {
|
|
871
1787
|
additionalHeaders = {};
|
|
872
1788
|
apiKey;
|
|
@@ -883,11 +1799,17 @@ var Schematic = class {
|
|
|
883
1799
|
isPending = true;
|
|
884
1800
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
885
1801
|
planListeners = /* @__PURE__ */ new Set();
|
|
1802
|
+
creditBalanceListeners = /* @__PURE__ */ new Set();
|
|
886
1803
|
storage;
|
|
1804
|
+
persistFlagState = true;
|
|
1805
|
+
flagStateCacheKey;
|
|
1806
|
+
flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
|
|
1807
|
+
cachedFlagState = null;
|
|
887
1808
|
useWebSocket = false;
|
|
888
1809
|
checks = {};
|
|
889
1810
|
featureUsageEventMap = {};
|
|
890
1811
|
planChecks = {};
|
|
1812
|
+
creditBalances = {};
|
|
891
1813
|
webSocketUrl = "wss://api.schematichq.com";
|
|
892
1814
|
webSocketConnectionTimeout = 1e4;
|
|
893
1815
|
webSocketReconnect = true;
|
|
@@ -916,11 +1838,16 @@ var Schematic = class {
|
|
|
916
1838
|
fallbackCheckCache = {};
|
|
917
1839
|
constructor(apiKey, options) {
|
|
918
1840
|
this.apiKey = apiKey;
|
|
1841
|
+
this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
|
|
919
1842
|
this.eventQueue = [];
|
|
920
1843
|
this.contextDependentEventQueue = [];
|
|
921
1844
|
this.useWebSocket = options?.useWebSocket ?? false;
|
|
922
1845
|
this.debugEnabled = options?.debug ?? false;
|
|
923
1846
|
this.offlineEnabled = options?.offline ?? false;
|
|
1847
|
+
this.persistFlagState = options?.persistFlagState ?? true;
|
|
1848
|
+
if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
|
|
1849
|
+
this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
|
|
1850
|
+
}
|
|
924
1851
|
if (typeof window !== "undefined" && typeof window.location !== "undefined") {
|
|
925
1852
|
const params = new URLSearchParams(window.location.search);
|
|
926
1853
|
const debugParam = params.get("schematic_debug");
|
|
@@ -953,6 +1880,7 @@ var Schematic = class {
|
|
|
953
1880
|
} catch {
|
|
954
1881
|
}
|
|
955
1882
|
}
|
|
1883
|
+
this.hydrateFlagStateFromCache();
|
|
956
1884
|
if (options?.apiUrl !== void 0) {
|
|
957
1885
|
this.apiUrl = options.apiUrl;
|
|
958
1886
|
}
|
|
@@ -1246,6 +2174,29 @@ var Schematic = class {
|
|
|
1246
2174
|
});
|
|
1247
2175
|
this.notifyPlanListeners(plan);
|
|
1248
2176
|
}
|
|
2177
|
+
if (message.credit_balances !== void 0 && message.credit_balances !== null) {
|
|
2178
|
+
const contextStr = contextString(context);
|
|
2179
|
+
const updates = CreditBalancesFromJSON(message.credit_balances);
|
|
2180
|
+
const previous = this.creditBalances[contextStr] ?? {};
|
|
2181
|
+
let changed = false;
|
|
2182
|
+
const merged = { ...previous };
|
|
2183
|
+
for (const [creditId, next] of Object.entries(updates)) {
|
|
2184
|
+
const current = previous[creditId];
|
|
2185
|
+
if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
|
|
2186
|
+
merged[creditId] = next;
|
|
2187
|
+
changed = true;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
if (changed) {
|
|
2191
|
+
this.creditBalances[contextStr] = merged;
|
|
2192
|
+
this.debug(
|
|
2193
|
+
`WebSocket credit balance update received. Notifying listeners`,
|
|
2194
|
+
{ creditBalances: merged }
|
|
2195
|
+
);
|
|
2196
|
+
this.notifyCreditBalanceListeners(merged);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
this.persistContextToCache(contextString(context));
|
|
1249
2200
|
this.flushContextDependentEventQueue();
|
|
1250
2201
|
this.setIsPending(false);
|
|
1251
2202
|
};
|
|
@@ -1353,7 +2304,32 @@ var Schematic = class {
|
|
|
1353
2304
|
return;
|
|
1354
2305
|
}
|
|
1355
2306
|
try {
|
|
1356
|
-
|
|
2307
|
+
const newContextStr = contextString(context);
|
|
2308
|
+
const cacheHit = this.hasCachedValuesForContext(newContextStr);
|
|
2309
|
+
if (cacheHit) {
|
|
2310
|
+
this.debug(
|
|
2311
|
+
`setContext: cache hit for context, pre-resolving from cached values`
|
|
2312
|
+
);
|
|
2313
|
+
this.context = context;
|
|
2314
|
+
this.flushContextDependentEventQueue();
|
|
2315
|
+
this.setIsPending(false);
|
|
2316
|
+
const cachedChecks = this.checks[newContextStr] ?? {};
|
|
2317
|
+
for (const [flagKey, check] of Object.entries(cachedChecks)) {
|
|
2318
|
+
if (check === void 0) continue;
|
|
2319
|
+
this.notifyFlagCheckListeners(flagKey, check);
|
|
2320
|
+
this.notifyFlagValueListeners(flagKey, check.value);
|
|
2321
|
+
}
|
|
2322
|
+
const cachedPlan = this.planChecks[newContextStr];
|
|
2323
|
+
if (cachedPlan !== void 0) {
|
|
2324
|
+
this.notifyPlanListeners(cachedPlan);
|
|
2325
|
+
}
|
|
2326
|
+
const cachedCreditBalances = this.creditBalances[newContextStr];
|
|
2327
|
+
if (cachedCreditBalances !== void 0) {
|
|
2328
|
+
this.notifyCreditBalanceListeners(cachedCreditBalances);
|
|
2329
|
+
}
|
|
2330
|
+
} else {
|
|
2331
|
+
this.setIsPending(true);
|
|
2332
|
+
}
|
|
1357
2333
|
if (!this.conn) {
|
|
1358
2334
|
if (this.isConnecting) {
|
|
1359
2335
|
this.debug(
|
|
@@ -1364,7 +2340,7 @@ var Schematic = class {
|
|
|
1364
2340
|
}
|
|
1365
2341
|
if (this.conn !== null) {
|
|
1366
2342
|
const socket2 = await this.conn;
|
|
1367
|
-
await this.wsSendMessage(socket2, context);
|
|
2343
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1368
2344
|
return;
|
|
1369
2345
|
}
|
|
1370
2346
|
}
|
|
@@ -1380,7 +2356,7 @@ var Schematic = class {
|
|
|
1380
2356
|
this.conn = this.wsConnect();
|
|
1381
2357
|
const socket2 = await this.conn;
|
|
1382
2358
|
this.isConnecting = false;
|
|
1383
|
-
await this.wsSendMessage(socket2, context);
|
|
2359
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1384
2360
|
return;
|
|
1385
2361
|
} catch (error) {
|
|
1386
2362
|
this.isConnecting = false;
|
|
@@ -1388,7 +2364,7 @@ var Schematic = class {
|
|
|
1388
2364
|
}
|
|
1389
2365
|
}
|
|
1390
2366
|
const socket = await this.conn;
|
|
1391
|
-
await this.wsSendMessage(socket, context);
|
|
2367
|
+
await this.wsSendMessage(socket, context, cacheHit);
|
|
1392
2368
|
} catch (error) {
|
|
1393
2369
|
console.warn("Failed to establish WebSocket connection:", error);
|
|
1394
2370
|
this.context = context;
|
|
@@ -1448,10 +2424,12 @@ var Schematic = class {
|
|
|
1448
2424
|
`Optimistically updating feature usage for event: ${eventName}`,
|
|
1449
2425
|
{ quantity }
|
|
1450
2426
|
);
|
|
2427
|
+
let dirty = false;
|
|
1451
2428
|
Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
|
|
1452
2429
|
if (check === void 0) return;
|
|
1453
2430
|
const updatedCheck = { ...check };
|
|
1454
2431
|
if (typeof updatedCheck.featureUsage === "number") {
|
|
2432
|
+
dirty = true;
|
|
1455
2433
|
updatedCheck.featureUsage += quantity;
|
|
1456
2434
|
if (typeof updatedCheck.featureAllocation === "number") {
|
|
1457
2435
|
const wasExceeded = updatedCheck.featureUsageExceeded === true;
|
|
@@ -1481,6 +2459,9 @@ var Schematic = class {
|
|
|
1481
2459
|
this.notifyFlagValueListeners(flagKey, updatedCheck.value);
|
|
1482
2460
|
}
|
|
1483
2461
|
});
|
|
2462
|
+
if (dirty) {
|
|
2463
|
+
this.persistContextToCache(contextString(this.context));
|
|
2464
|
+
}
|
|
1484
2465
|
};
|
|
1485
2466
|
/**
|
|
1486
2467
|
* Event processing
|
|
@@ -1583,6 +2564,206 @@ var Schematic = class {
|
|
|
1583
2564
|
this.storage.setItem(anonymousIdKey, generatedAnonymousId);
|
|
1584
2565
|
return generatedAnonymousId;
|
|
1585
2566
|
};
|
|
2567
|
+
hasCachedValuesForContext = (contextStr) => {
|
|
2568
|
+
const cachedChecks = this.checks[contextStr];
|
|
2569
|
+
if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
|
|
2570
|
+
return true;
|
|
2571
|
+
}
|
|
2572
|
+
if (this.planChecks[contextStr] !== void 0) {
|
|
2573
|
+
return true;
|
|
2574
|
+
}
|
|
2575
|
+
const cachedCreditBalances = this.creditBalances[contextStr];
|
|
2576
|
+
return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
|
|
2577
|
+
};
|
|
2578
|
+
readFlagStateCache = () => {
|
|
2579
|
+
if (!this.persistFlagState || this.storage === void 0) {
|
|
2580
|
+
return null;
|
|
2581
|
+
}
|
|
2582
|
+
let raw;
|
|
2583
|
+
try {
|
|
2584
|
+
raw = this.storage.getItem(this.flagStateCacheKey);
|
|
2585
|
+
} catch (error) {
|
|
2586
|
+
this.debug("Failed to read flag state cache:", error);
|
|
2587
|
+
return null;
|
|
2588
|
+
}
|
|
2589
|
+
if (raw === null || raw === void 0) {
|
|
2590
|
+
return null;
|
|
2591
|
+
}
|
|
2592
|
+
let parsed;
|
|
2593
|
+
try {
|
|
2594
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
2595
|
+
} catch (error) {
|
|
2596
|
+
this.debug("Flag state cache is not valid JSON, ignoring:", error);
|
|
2597
|
+
return null;
|
|
2598
|
+
}
|
|
2599
|
+
if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
|
|
2600
|
+
this.debug(
|
|
2601
|
+
`Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
|
|
2602
|
+
{
|
|
2603
|
+
parsedType: typeof parsed,
|
|
2604
|
+
version: parsed?.version
|
|
2605
|
+
}
|
|
2606
|
+
);
|
|
2607
|
+
return null;
|
|
2608
|
+
}
|
|
2609
|
+
return parsed;
|
|
2610
|
+
};
|
|
2611
|
+
reviveCachedCheck = (raw) => {
|
|
2612
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2613
|
+
const obj = raw;
|
|
2614
|
+
if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
|
|
2615
|
+
return null;
|
|
2616
|
+
}
|
|
2617
|
+
const revived = { ...obj };
|
|
2618
|
+
if (typeof revived.featureUsageResetAt === "string") {
|
|
2619
|
+
const d = new Date(revived.featureUsageResetAt);
|
|
2620
|
+
revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
|
|
2621
|
+
}
|
|
2622
|
+
return revived;
|
|
2623
|
+
};
|
|
2624
|
+
reviveCachedPlan = (raw) => {
|
|
2625
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2626
|
+
const obj = raw;
|
|
2627
|
+
if (typeof obj.id !== "string" || typeof obj.name !== "string") {
|
|
2628
|
+
return null;
|
|
2629
|
+
}
|
|
2630
|
+
const revived = { ...obj };
|
|
2631
|
+
if (typeof revived.trialEndDate === "string") {
|
|
2632
|
+
const d = new Date(revived.trialEndDate);
|
|
2633
|
+
revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
|
|
2634
|
+
}
|
|
2635
|
+
return revived;
|
|
2636
|
+
};
|
|
2637
|
+
reviveCachedCreditBalances = (raw) => {
|
|
2638
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2639
|
+
const revived = {};
|
|
2640
|
+
for (const [creditId, value] of Object.entries(
|
|
2641
|
+
raw
|
|
2642
|
+
)) {
|
|
2643
|
+
if (value === null || typeof value !== "object") continue;
|
|
2644
|
+
const obj = value;
|
|
2645
|
+
if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
|
|
2646
|
+
continue;
|
|
2647
|
+
}
|
|
2648
|
+
revived[creditId] = {
|
|
2649
|
+
remaining: obj.remaining,
|
|
2650
|
+
reserved: obj.reserved,
|
|
2651
|
+
settled: obj.settled
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
return Object.keys(revived).length > 0 ? revived : null;
|
|
2655
|
+
};
|
|
2656
|
+
hydrateFlagStateFromCache = () => {
|
|
2657
|
+
const parsed = this.readFlagStateCache();
|
|
2658
|
+
if (parsed === null) return;
|
|
2659
|
+
const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
|
|
2660
|
+
const fresh = {};
|
|
2661
|
+
let contextsLoaded = 0;
|
|
2662
|
+
let contextsExpired = 0;
|
|
2663
|
+
for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
|
|
2664
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2665
|
+
if (typeof entry.updatedAt !== "number") continue;
|
|
2666
|
+
if (entry.updatedAt < cutoff) {
|
|
2667
|
+
contextsExpired += 1;
|
|
2668
|
+
continue;
|
|
2669
|
+
}
|
|
2670
|
+
const revivedChecks = {};
|
|
2671
|
+
if (entry.checks !== null && typeof entry.checks === "object") {
|
|
2672
|
+
for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
|
|
2673
|
+
const revived = this.reviveCachedCheck(rawCheck);
|
|
2674
|
+
if (revived === null || revived.flag !== flagKey) continue;
|
|
2675
|
+
revivedChecks[flagKey] = revived;
|
|
2676
|
+
if (typeof revived.featureUsageEvent === "string") {
|
|
2677
|
+
this.updateFeatureUsageEventMap(revived);
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
if (Object.keys(revivedChecks).length > 0) {
|
|
2681
|
+
this.checks[contextStr] = revivedChecks;
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
let revivedPlan;
|
|
2685
|
+
if (entry.plan !== void 0 && entry.plan !== null) {
|
|
2686
|
+
const p = this.reviveCachedPlan(entry.plan);
|
|
2687
|
+
if (p !== null) {
|
|
2688
|
+
revivedPlan = p;
|
|
2689
|
+
this.planChecks[contextStr] = p;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
let revivedCreditBalances;
|
|
2693
|
+
if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
|
|
2694
|
+
const balances = this.reviveCachedCreditBalances(entry.creditBalances);
|
|
2695
|
+
if (balances !== null) {
|
|
2696
|
+
revivedCreditBalances = balances;
|
|
2697
|
+
this.creditBalances[contextStr] = balances;
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
fresh[contextStr] = {
|
|
2701
|
+
checks: revivedChecks,
|
|
2702
|
+
plan: revivedPlan,
|
|
2703
|
+
creditBalances: revivedCreditBalances,
|
|
2704
|
+
updatedAt: entry.updatedAt
|
|
2705
|
+
};
|
|
2706
|
+
contextsLoaded += 1;
|
|
2707
|
+
}
|
|
2708
|
+
this.cachedFlagState = { version: cacheVersion, contexts: fresh };
|
|
2709
|
+
this.debug(
|
|
2710
|
+
`Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
|
|
2711
|
+
);
|
|
2712
|
+
};
|
|
2713
|
+
persistContextToCache = (contextStr) => {
|
|
2714
|
+
const checksForContext = this.checks[contextStr];
|
|
2715
|
+
const planForContext = this.planChecks[contextStr];
|
|
2716
|
+
const creditBalancesForContext = this.creditBalances[contextStr];
|
|
2717
|
+
if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
|
|
2718
|
+
return;
|
|
2719
|
+
}
|
|
2720
|
+
if (this.cachedFlagState === null) {
|
|
2721
|
+
this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
|
|
2722
|
+
version: cacheVersion,
|
|
2723
|
+
contexts: {}
|
|
2724
|
+
};
|
|
2725
|
+
}
|
|
2726
|
+
const cleanChecks = {};
|
|
2727
|
+
if (checksForContext !== void 0) {
|
|
2728
|
+
for (const [flagKey, check] of Object.entries(checksForContext)) {
|
|
2729
|
+
if (check !== void 0) cleanChecks[flagKey] = check;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
this.cachedFlagState.contexts[contextStr] = {
|
|
2733
|
+
checks: cleanChecks,
|
|
2734
|
+
plan: planForContext,
|
|
2735
|
+
creditBalances: creditBalancesForContext,
|
|
2736
|
+
updatedAt: Date.now()
|
|
2737
|
+
};
|
|
2738
|
+
const entries = Object.entries(this.cachedFlagState.contexts);
|
|
2739
|
+
if (entries.length > flagStateCacheMaxContexts) {
|
|
2740
|
+
entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
|
2741
|
+
const survivors = entries.slice(0, flagStateCacheMaxContexts);
|
|
2742
|
+
const survivorKeys = new Set(survivors.map(([k]) => k));
|
|
2743
|
+
for (const key of Object.keys(this.checks)) {
|
|
2744
|
+
if (!survivorKeys.has(key)) delete this.checks[key];
|
|
2745
|
+
}
|
|
2746
|
+
for (const key of Object.keys(this.planChecks)) {
|
|
2747
|
+
if (!survivorKeys.has(key)) delete this.planChecks[key];
|
|
2748
|
+
}
|
|
2749
|
+
for (const key of Object.keys(this.creditBalances)) {
|
|
2750
|
+
if (!survivorKeys.has(key)) delete this.creditBalances[key];
|
|
2751
|
+
}
|
|
2752
|
+
this.cachedFlagState = {
|
|
2753
|
+
version: cacheVersion,
|
|
2754
|
+
contexts: Object.fromEntries(survivors)
|
|
2755
|
+
};
|
|
2756
|
+
}
|
|
2757
|
+
if (!this.persistFlagState || this.storage === void 0) return;
|
|
2758
|
+
try {
|
|
2759
|
+
this.storage.setItem(
|
|
2760
|
+
this.flagStateCacheKey,
|
|
2761
|
+
JSON.stringify(this.cachedFlagState)
|
|
2762
|
+
);
|
|
2763
|
+
} catch (error) {
|
|
2764
|
+
this.debug("Failed to write flag state cache:", error);
|
|
2765
|
+
}
|
|
2766
|
+
};
|
|
1586
2767
|
handleEvent = (eventType, eventBody) => {
|
|
1587
2768
|
const event = {
|
|
1588
2769
|
api_key: this.apiKey,
|
|
@@ -1843,6 +3024,9 @@ var Schematic = class {
|
|
|
1843
3024
|
if (this.conn !== null) {
|
|
1844
3025
|
try {
|
|
1845
3026
|
const socket = await this.conn;
|
|
3027
|
+
if (this.currentWebSocket === socket) {
|
|
3028
|
+
this.currentWebSocket = null;
|
|
3029
|
+
}
|
|
1846
3030
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
1847
3031
|
socket.close();
|
|
1848
3032
|
}
|
|
@@ -2008,6 +3192,7 @@ var Schematic = class {
|
|
|
2008
3192
|
this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
|
|
2009
3193
|
let timeoutId = null;
|
|
2010
3194
|
let isResolved = false;
|
|
3195
|
+
let didOpen = false;
|
|
2011
3196
|
timeoutId = setTimeout(() => {
|
|
2012
3197
|
if (!isResolved) {
|
|
2013
3198
|
isResolved = true;
|
|
@@ -2021,6 +3206,7 @@ var Schematic = class {
|
|
|
2021
3206
|
webSocket.onopen = () => {
|
|
2022
3207
|
if (isResolved) return;
|
|
2023
3208
|
isResolved = true;
|
|
3209
|
+
didOpen = true;
|
|
2024
3210
|
if (timeoutId !== null) {
|
|
2025
3211
|
clearTimeout(timeoutId);
|
|
2026
3212
|
}
|
|
@@ -2046,11 +3232,12 @@ var Schematic = class {
|
|
|
2046
3232
|
}
|
|
2047
3233
|
this.debug(`WebSocket connection ${connectionId} closed`);
|
|
2048
3234
|
this.conn = null;
|
|
3235
|
+
const wasCurrent = this.currentWebSocket === webSocket;
|
|
2049
3236
|
if (this.currentWebSocket === webSocket) {
|
|
2050
3237
|
this.currentWebSocket = null;
|
|
2051
3238
|
this.isConnecting = false;
|
|
2052
3239
|
}
|
|
2053
|
-
if (
|
|
3240
|
+
if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
|
|
2054
3241
|
this.attemptReconnect();
|
|
2055
3242
|
}
|
|
2056
3243
|
};
|
|
@@ -2146,6 +3333,16 @@ var Schematic = class {
|
|
|
2146
3333
|
const plan = this.planChecks[contextStr];
|
|
2147
3334
|
return plan;
|
|
2148
3335
|
};
|
|
3336
|
+
/** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
|
|
3337
|
+
getCreditBalances = () => {
|
|
3338
|
+
const contextStr = contextString(this.context);
|
|
3339
|
+
return this.creditBalances[contextStr] ?? emptyCreditBalances;
|
|
3340
|
+
};
|
|
3341
|
+
/** Get the company's lease-aware balance for a single credit type in the current context */
|
|
3342
|
+
getCreditBalance = (creditId) => {
|
|
3343
|
+
const contextStr = contextString(this.context);
|
|
3344
|
+
return this.creditBalances[contextStr]?.[creditId];
|
|
3345
|
+
};
|
|
2149
3346
|
// flag checks state
|
|
2150
3347
|
getFlagCheck = (flagKey) => {
|
|
2151
3348
|
const contextStr = contextString(this.context);
|
|
@@ -2205,6 +3402,13 @@ var Schematic = class {
|
|
|
2205
3402
|
this.planListeners.delete(listener);
|
|
2206
3403
|
};
|
|
2207
3404
|
};
|
|
3405
|
+
/** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
|
|
3406
|
+
addCreditBalanceListener = (listener) => {
|
|
3407
|
+
this.creditBalanceListeners.add(listener);
|
|
3408
|
+
return () => {
|
|
3409
|
+
this.creditBalanceListeners.delete(listener);
|
|
3410
|
+
};
|
|
3411
|
+
};
|
|
2208
3412
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2209
3413
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2210
3414
|
if (listeners.size > 0) {
|
|
@@ -2268,6 +3472,17 @@ var Schematic = class {
|
|
|
2268
3472
|
});
|
|
2269
3473
|
});
|
|
2270
3474
|
};
|
|
3475
|
+
notifyCreditBalanceListeners = (value) => {
|
|
3476
|
+
const listeners = this.creditBalanceListeners ?? [];
|
|
3477
|
+
if (listeners.size > 0) {
|
|
3478
|
+
this.debug(`Notifying ${listeners.size} credit balance listeners`, {
|
|
3479
|
+
value
|
|
3480
|
+
});
|
|
3481
|
+
}
|
|
3482
|
+
listeners.forEach(
|
|
3483
|
+
(listener) => notifyCreditBalanceListener(listener, value)
|
|
3484
|
+
);
|
|
3485
|
+
};
|
|
2271
3486
|
};
|
|
2272
3487
|
var notifyPendingListener = (listener, value) => {
|
|
2273
3488
|
if (listener.length > 0) {
|
|
@@ -2297,16 +3512,36 @@ var notifyPlanListener = (listener, value) => {
|
|
|
2297
3512
|
listener();
|
|
2298
3513
|
}
|
|
2299
3514
|
};
|
|
3515
|
+
var notifyCreditBalanceListener = (listener, value) => {
|
|
3516
|
+
if (listener.length > 0) {
|
|
3517
|
+
listener(value);
|
|
3518
|
+
} else {
|
|
3519
|
+
listener();
|
|
3520
|
+
}
|
|
3521
|
+
};
|
|
2300
3522
|
export {
|
|
2301
3523
|
CheckFlagResponseFromJSON,
|
|
2302
3524
|
CheckFlagReturnFromJSON,
|
|
2303
3525
|
CheckFlagsResponseFromJSON,
|
|
2304
3526
|
CheckPlanReturnFromJSON,
|
|
3527
|
+
CreditBalancesFromJSON,
|
|
3528
|
+
DEFAULT_INVOICE_QUERY,
|
|
2305
3529
|
DatastreamCompanyPlanFromJSON,
|
|
2306
3530
|
EventBodyFlagCheckToJSON,
|
|
3531
|
+
INVOICE_MAX_PAGE_SIZE,
|
|
3532
|
+
INVOICE_PAGE_SIZE,
|
|
3533
|
+
InvoiceStatus,
|
|
2307
3534
|
RuleType,
|
|
2308
3535
|
Schematic,
|
|
3536
|
+
SchematicApiError,
|
|
3537
|
+
SchematicBillingClient,
|
|
3538
|
+
SchematicSession,
|
|
3539
|
+
TOKEN_CACHE_SIZE,
|
|
2309
3540
|
TrialStatus,
|
|
2310
|
-
UsagePeriod
|
|
3541
|
+
UsagePeriod,
|
|
3542
|
+
models_exports as billingApi,
|
|
3543
|
+
fetchBillingData,
|
|
3544
|
+
normalizeInvoiceQuery,
|
|
3545
|
+
sessionKey
|
|
2311
3546
|
};
|
|
2312
3547
|
/* @preserve */
|