@schematichq/schematic-react 1.4.1 → 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 +72 -1
- package/dist/schematic-react.cjs.js +2266 -200
- package/dist/schematic-react.d.ts +847 -22
- package/dist/schematic-react.esm.js +2267 -201
- package/package.json +27 -31
|
@@ -30,22 +30,38 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
BillingDataProvider: () => BillingDataProvider,
|
|
34
|
+
BillingProvider: () => BillingProvider,
|
|
35
|
+
DEFAULT_INVOICE_QUERY: () => DEFAULT_INVOICE_QUERY,
|
|
36
|
+
INVOICE_PAGE_SIZE: () => INVOICE_PAGE_SIZE,
|
|
37
|
+
InvoiceStatus: () => InvoiceStatus,
|
|
33
38
|
RuleType: () => RuleType,
|
|
34
39
|
Schematic: () => Schematic,
|
|
40
|
+
SchematicI18nContext: () => SchematicI18nContext,
|
|
41
|
+
SchematicI18nProvider: () => SchematicI18nProvider,
|
|
35
42
|
SchematicProvider: () => SchematicProvider,
|
|
36
43
|
TrialStatus: () => TrialStatus,
|
|
37
44
|
UsagePeriod: () => UsagePeriod,
|
|
45
|
+
normalizeInvoiceQuery: () => normalizeInvoiceQuery2,
|
|
46
|
+
useBillingDataSource: () => useBillingDataSource,
|
|
47
|
+
useInvalidateBillingData: () => useInvalidateBillingData,
|
|
48
|
+
useInvoices: () => useInvoices,
|
|
38
49
|
useSchematic: () => useSchematic,
|
|
39
50
|
useSchematicContext: () => useSchematicContext,
|
|
51
|
+
useSchematicCreditBalance: () => useSchematicCreditBalance,
|
|
40
52
|
useSchematicEntitlement: () => useSchematicEntitlement,
|
|
41
53
|
useSchematicEvents: () => useSchematicEvents,
|
|
42
54
|
useSchematicFlag: () => useSchematicFlag,
|
|
55
|
+
useSchematicI18n: () => useSchematicI18n,
|
|
43
56
|
useSchematicIsPending: () => useSchematicIsPending,
|
|
44
|
-
|
|
57
|
+
useSchematicLocale: () => useSchematicLocale,
|
|
58
|
+
useSchematicPlan: () => useSchematicPlan,
|
|
59
|
+
useSchematicStrings: () => useSchematicStrings,
|
|
60
|
+
useSchematicTranslate: () => useSchematicTranslate
|
|
45
61
|
});
|
|
46
62
|
module.exports = __toCommonJS(index_exports);
|
|
47
63
|
|
|
48
|
-
// node_modules/@schematichq/schematic-js/dist/schematic.esm.js
|
|
64
|
+
// node_modules/.pnpm/@schematichq+schematic-js@1.7.0/node_modules/@schematichq/schematic-js/dist/schematic.esm.js
|
|
49
65
|
var __create2 = Object.create;
|
|
50
66
|
var __defProp2 = Object.defineProperty;
|
|
51
67
|
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
@@ -53,7 +69,15 @@ var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
|
53
69
|
var __getProtoOf2 = Object.getPrototypeOf;
|
|
54
70
|
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
55
71
|
var __commonJS = (cb, mod) => function __require() {
|
|
56
|
-
|
|
72
|
+
try {
|
|
73
|
+
return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
throw mod = 0, e;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var __export2 = (target, all) => {
|
|
79
|
+
for (var name in all)
|
|
80
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
57
81
|
};
|
|
58
82
|
var __copyProps2 = (to, from, except, desc) => {
|
|
59
83
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -72,7 +96,7 @@ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__
|
|
|
72
96
|
mod
|
|
73
97
|
));
|
|
74
98
|
var require_browser_polyfill = __commonJS({
|
|
75
|
-
"node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
|
|
99
|
+
"node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
|
|
76
100
|
(function(self2) {
|
|
77
101
|
var irrelevant = (function(exports2) {
|
|
78
102
|
var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
|
|
@@ -612,19 +636,16 @@ for (let i = 0; i < 256; ++i) {
|
|
|
612
636
|
function unsafeStringify(arr, offset = 0) {
|
|
613
637
|
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
614
638
|
}
|
|
615
|
-
var getRandomValues;
|
|
616
639
|
var rnds8 = new Uint8Array(16);
|
|
617
640
|
function rng() {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
641
|
+
return crypto.getRandomValues(rnds8);
|
|
642
|
+
}
|
|
643
|
+
function v4(options, buf, offset) {
|
|
644
|
+
if (!buf && !options && crypto.randomUUID) {
|
|
645
|
+
return crypto.randomUUID();
|
|
623
646
|
}
|
|
624
|
-
return
|
|
647
|
+
return _v4(options, buf, offset);
|
|
625
648
|
}
|
|
626
|
-
var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
627
|
-
var native_default = { randomUUID };
|
|
628
649
|
function _v4(options, buf, offset) {
|
|
629
650
|
options = options || {};
|
|
630
651
|
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
@@ -645,12 +666,6 @@ function _v4(options, buf, offset) {
|
|
|
645
666
|
}
|
|
646
667
|
return unsafeStringify(rnds);
|
|
647
668
|
}
|
|
648
|
-
function v4(options, buf, offset) {
|
|
649
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
650
|
-
return native_default.randomUUID();
|
|
651
|
-
}
|
|
652
|
-
return _v4(options, buf, offset);
|
|
653
|
-
}
|
|
654
669
|
var v4_default = v4;
|
|
655
670
|
var import_polyfill = __toESM2(require_browser_polyfill());
|
|
656
671
|
function EntitlementValueTypeFromJSON(json) {
|
|
@@ -659,6 +674,30 @@ function EntitlementValueTypeFromJSON(json) {
|
|
|
659
674
|
function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
660
675
|
return json;
|
|
661
676
|
}
|
|
677
|
+
function MetricPeriodMonthResetFromJSON(json) {
|
|
678
|
+
return MetricPeriodMonthResetFromJSONTyped(json, false);
|
|
679
|
+
}
|
|
680
|
+
function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
|
|
681
|
+
return json;
|
|
682
|
+
}
|
|
683
|
+
function WarningTierFromJSON(json) {
|
|
684
|
+
return WarningTierFromJSONTyped(json, false);
|
|
685
|
+
}
|
|
686
|
+
function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
|
|
687
|
+
if (json == null) {
|
|
688
|
+
return json;
|
|
689
|
+
}
|
|
690
|
+
return {
|
|
691
|
+
key: json["key"],
|
|
692
|
+
value: json["value"]
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function MetricPeriodFromJSON(json) {
|
|
696
|
+
return MetricPeriodFromJSONTyped(json, false);
|
|
697
|
+
}
|
|
698
|
+
function MetricPeriodFromJSONTyped(json, ignoreDiscriminator) {
|
|
699
|
+
return json;
|
|
700
|
+
}
|
|
662
701
|
function FeatureEntitlementFromJSON(json) {
|
|
663
702
|
return FeatureEntitlementFromJSONTyped(json, false);
|
|
664
703
|
}
|
|
@@ -668,21 +707,32 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
668
707
|
}
|
|
669
708
|
return {
|
|
670
709
|
allocation: json["allocation"] == null ? void 0 : json["allocation"],
|
|
710
|
+
consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
|
|
671
711
|
creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
|
|
672
712
|
creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
|
|
713
|
+
creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
|
|
714
|
+
creditSettled: json["credit_settled"] == null ? void 0 : json["credit_settled"],
|
|
673
715
|
creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
|
|
674
716
|
creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
|
|
675
717
|
eventName: json["event_name"] == null ? void 0 : json["event_name"],
|
|
718
|
+
eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
|
|
676
719
|
featureId: json["feature_id"],
|
|
677
720
|
featureKey: json["feature_key"],
|
|
678
|
-
metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
|
|
721
|
+
metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
|
|
679
722
|
metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
|
|
680
|
-
monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
|
|
723
|
+
monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
|
|
681
724
|
softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
|
|
682
725
|
usage: json["usage"] == null ? void 0 : json["usage"],
|
|
683
|
-
valueType: EntitlementValueTypeFromJSON(json["value_type"])
|
|
726
|
+
valueType: EntitlementValueTypeFromJSON(json["value_type"]),
|
|
727
|
+
warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
|
|
684
728
|
};
|
|
685
729
|
}
|
|
730
|
+
function RuleTypeFromJSON(json) {
|
|
731
|
+
return RuleTypeFromJSONTyped(json, false);
|
|
732
|
+
}
|
|
733
|
+
function RuleTypeFromJSONTyped(json, ignoreDiscriminator) {
|
|
734
|
+
return json;
|
|
735
|
+
}
|
|
686
736
|
function CheckFlagResponseDataFromJSON(json) {
|
|
687
737
|
return CheckFlagResponseDataFromJSONTyped(json, false);
|
|
688
738
|
}
|
|
@@ -697,13 +747,13 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
697
747
|
featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
|
|
698
748
|
featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
|
|
699
749
|
featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
|
|
700
|
-
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
|
|
750
|
+
featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : MetricPeriodFromJSON(json["feature_usage_period"]),
|
|
701
751
|
featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
|
|
702
752
|
flag: json["flag"],
|
|
703
753
|
flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
|
|
704
754
|
reason: json["reason"],
|
|
705
755
|
ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
|
|
706
|
-
ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
|
|
756
|
+
ruleType: json["rule_type"] == null ? void 0 : RuleTypeFromJSON(json["rule_type"]),
|
|
707
757
|
userId: json["user_id"] == null ? void 0 : json["user_id"],
|
|
708
758
|
value: json["value"]
|
|
709
759
|
};
|
|
@@ -720,6 +770,268 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
720
770
|
params: json["params"]
|
|
721
771
|
};
|
|
722
772
|
}
|
|
773
|
+
var BASE_PATH = "https://api.schematichq.com".replace(/\/+$/, "");
|
|
774
|
+
var Configuration = class {
|
|
775
|
+
constructor(configuration = {}) {
|
|
776
|
+
this.configuration = configuration;
|
|
777
|
+
}
|
|
778
|
+
configuration;
|
|
779
|
+
set config(configuration) {
|
|
780
|
+
this.configuration = configuration;
|
|
781
|
+
}
|
|
782
|
+
get basePath() {
|
|
783
|
+
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
|
784
|
+
}
|
|
785
|
+
get fetchApi() {
|
|
786
|
+
return this.configuration.fetchApi;
|
|
787
|
+
}
|
|
788
|
+
get middleware() {
|
|
789
|
+
return this.configuration.middleware || [];
|
|
790
|
+
}
|
|
791
|
+
get queryParamsStringify() {
|
|
792
|
+
return this.configuration.queryParamsStringify || querystring;
|
|
793
|
+
}
|
|
794
|
+
get username() {
|
|
795
|
+
return this.configuration.username;
|
|
796
|
+
}
|
|
797
|
+
get password() {
|
|
798
|
+
return this.configuration.password;
|
|
799
|
+
}
|
|
800
|
+
get apiKey() {
|
|
801
|
+
const apiKey = this.configuration.apiKey;
|
|
802
|
+
if (apiKey) {
|
|
803
|
+
return typeof apiKey === "function" ? apiKey : () => apiKey;
|
|
804
|
+
}
|
|
805
|
+
return void 0;
|
|
806
|
+
}
|
|
807
|
+
get accessToken() {
|
|
808
|
+
const accessToken = this.configuration.accessToken;
|
|
809
|
+
if (accessToken) {
|
|
810
|
+
return typeof accessToken === "function" ? accessToken : async () => accessToken;
|
|
811
|
+
}
|
|
812
|
+
return void 0;
|
|
813
|
+
}
|
|
814
|
+
get headers() {
|
|
815
|
+
return this.configuration.headers;
|
|
816
|
+
}
|
|
817
|
+
get credentials() {
|
|
818
|
+
return this.configuration.credentials;
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
var DefaultConfig = new Configuration();
|
|
822
|
+
var BaseAPI = class _BaseAPI {
|
|
823
|
+
constructor(configuration = DefaultConfig) {
|
|
824
|
+
this.configuration = configuration;
|
|
825
|
+
this.middleware = configuration.middleware;
|
|
826
|
+
}
|
|
827
|
+
configuration;
|
|
828
|
+
static jsonRegex = new RegExp(
|
|
829
|
+
"^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$",
|
|
830
|
+
"i"
|
|
831
|
+
);
|
|
832
|
+
middleware;
|
|
833
|
+
withMiddleware(...middlewares) {
|
|
834
|
+
const next = this.clone();
|
|
835
|
+
next.middleware = next.middleware.concat(...middlewares);
|
|
836
|
+
return next;
|
|
837
|
+
}
|
|
838
|
+
withPreMiddleware(...preMiddlewares) {
|
|
839
|
+
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
|
840
|
+
return this.withMiddleware(...middlewares);
|
|
841
|
+
}
|
|
842
|
+
withPostMiddleware(...postMiddlewares) {
|
|
843
|
+
const middlewares = postMiddlewares.map((post) => ({ post }));
|
|
844
|
+
return this.withMiddleware(...middlewares);
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Check if the given MIME is a JSON MIME.
|
|
848
|
+
* JSON MIME examples:
|
|
849
|
+
* application/json
|
|
850
|
+
* application/json; charset=UTF8
|
|
851
|
+
* APPLICATION/JSON
|
|
852
|
+
* application/vnd.company+json
|
|
853
|
+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
|
854
|
+
* @return True if the given MIME is JSON, false otherwise.
|
|
855
|
+
*/
|
|
856
|
+
isJsonMime(mime) {
|
|
857
|
+
if (!mime) {
|
|
858
|
+
return false;
|
|
859
|
+
}
|
|
860
|
+
return _BaseAPI.jsonRegex.test(mime);
|
|
861
|
+
}
|
|
862
|
+
async request(context, initOverrides) {
|
|
863
|
+
const { url, init } = await this.createFetchParams(context, initOverrides);
|
|
864
|
+
const response = await this.fetchApi(url, init);
|
|
865
|
+
if (response && response.status >= 200 && response.status < 300) {
|
|
866
|
+
return response;
|
|
867
|
+
}
|
|
868
|
+
throw new ResponseError(response, "Response returned an error code");
|
|
869
|
+
}
|
|
870
|
+
async createFetchParams(context, initOverrides) {
|
|
871
|
+
let url = this.configuration.basePath + context.path;
|
|
872
|
+
if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
|
|
873
|
+
url += "?" + this.configuration.queryParamsStringify(context.query);
|
|
874
|
+
}
|
|
875
|
+
const headers = Object.assign(
|
|
876
|
+
{},
|
|
877
|
+
this.configuration.headers,
|
|
878
|
+
context.headers
|
|
879
|
+
);
|
|
880
|
+
Object.keys(headers).forEach(
|
|
881
|
+
(key) => headers[key] === void 0 ? delete headers[key] : {}
|
|
882
|
+
);
|
|
883
|
+
const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides;
|
|
884
|
+
const initParams = {
|
|
885
|
+
method: context.method,
|
|
886
|
+
headers,
|
|
887
|
+
body: context.body,
|
|
888
|
+
credentials: this.configuration.credentials
|
|
889
|
+
};
|
|
890
|
+
const overriddenInit = {
|
|
891
|
+
...initParams,
|
|
892
|
+
...await initOverrideFn({
|
|
893
|
+
init: initParams,
|
|
894
|
+
context
|
|
895
|
+
})
|
|
896
|
+
};
|
|
897
|
+
let body;
|
|
898
|
+
if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
|
|
899
|
+
body = overriddenInit.body;
|
|
900
|
+
} else if (this.isJsonMime(headers["Content-Type"])) {
|
|
901
|
+
body = JSON.stringify(overriddenInit.body);
|
|
902
|
+
} else {
|
|
903
|
+
body = overriddenInit.body;
|
|
904
|
+
}
|
|
905
|
+
const init = {
|
|
906
|
+
...overriddenInit,
|
|
907
|
+
body
|
|
908
|
+
};
|
|
909
|
+
return { url, init };
|
|
910
|
+
}
|
|
911
|
+
fetchApi = async (url, init) => {
|
|
912
|
+
let fetchParams = { url, init };
|
|
913
|
+
for (const middleware of this.middleware) {
|
|
914
|
+
if (middleware.pre) {
|
|
915
|
+
fetchParams = await middleware.pre({
|
|
916
|
+
fetch: this.fetchApi,
|
|
917
|
+
...fetchParams
|
|
918
|
+
}) || fetchParams;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
let response = void 0;
|
|
922
|
+
try {
|
|
923
|
+
response = await (this.configuration.fetchApi || fetch)(
|
|
924
|
+
fetchParams.url,
|
|
925
|
+
fetchParams.init
|
|
926
|
+
);
|
|
927
|
+
} catch (e) {
|
|
928
|
+
for (const middleware of this.middleware) {
|
|
929
|
+
if (middleware.onError) {
|
|
930
|
+
response = await middleware.onError({
|
|
931
|
+
fetch: this.fetchApi,
|
|
932
|
+
url: fetchParams.url,
|
|
933
|
+
init: fetchParams.init,
|
|
934
|
+
error: e,
|
|
935
|
+
response: response ? response.clone() : void 0
|
|
936
|
+
}) || response;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (response === void 0) {
|
|
940
|
+
if (e instanceof Error) {
|
|
941
|
+
throw new FetchError(
|
|
942
|
+
e,
|
|
943
|
+
"The request failed and the interceptors did not return an alternative response"
|
|
944
|
+
);
|
|
945
|
+
} else {
|
|
946
|
+
throw e;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
for (const middleware of this.middleware) {
|
|
951
|
+
if (middleware.post) {
|
|
952
|
+
response = await middleware.post({
|
|
953
|
+
fetch: this.fetchApi,
|
|
954
|
+
url: fetchParams.url,
|
|
955
|
+
init: fetchParams.init,
|
|
956
|
+
response: response.clone()
|
|
957
|
+
}) || response;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return response;
|
|
961
|
+
};
|
|
962
|
+
/**
|
|
963
|
+
* Create a shallow clone of `this` by constructing a new instance
|
|
964
|
+
* and then shallow cloning data members.
|
|
965
|
+
*/
|
|
966
|
+
clone() {
|
|
967
|
+
const constructor = this.constructor;
|
|
968
|
+
const next = new constructor(this.configuration);
|
|
969
|
+
next.middleware = this.middleware.slice();
|
|
970
|
+
return next;
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
function isBlob(value) {
|
|
974
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
975
|
+
}
|
|
976
|
+
function isFormData(value) {
|
|
977
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
978
|
+
}
|
|
979
|
+
var ResponseError = class extends Error {
|
|
980
|
+
constructor(response, msg) {
|
|
981
|
+
super(msg);
|
|
982
|
+
this.response = response;
|
|
983
|
+
}
|
|
984
|
+
response;
|
|
985
|
+
name = "ResponseError";
|
|
986
|
+
};
|
|
987
|
+
var FetchError = class extends Error {
|
|
988
|
+
constructor(cause, msg) {
|
|
989
|
+
super(msg);
|
|
990
|
+
this.cause = cause;
|
|
991
|
+
}
|
|
992
|
+
cause;
|
|
993
|
+
name = "FetchError";
|
|
994
|
+
};
|
|
995
|
+
function querystring(params, prefix = "") {
|
|
996
|
+
return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
|
|
997
|
+
}
|
|
998
|
+
function querystringSingleKey(key, value, keyPrefix = "") {
|
|
999
|
+
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
|
1000
|
+
if (value instanceof Array) {
|
|
1001
|
+
const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
|
|
1002
|
+
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
|
1003
|
+
}
|
|
1004
|
+
if (value instanceof Set) {
|
|
1005
|
+
const valueAsArray = Array.from(value);
|
|
1006
|
+
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
|
1007
|
+
}
|
|
1008
|
+
if (value instanceof Date) {
|
|
1009
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
|
1010
|
+
}
|
|
1011
|
+
if (value instanceof Object) {
|
|
1012
|
+
return querystring(value, fullKey);
|
|
1013
|
+
}
|
|
1014
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
|
1015
|
+
}
|
|
1016
|
+
function mapValues(data, fn) {
|
|
1017
|
+
return Object.keys(data).reduce(
|
|
1018
|
+
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
|
1019
|
+
{}
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
function CompanyCreditBalanceFromJSON(json) {
|
|
1023
|
+
return CompanyCreditBalanceFromJSONTyped(json, false);
|
|
1024
|
+
}
|
|
1025
|
+
function CompanyCreditBalanceFromJSONTyped(json, ignoreDiscriminator) {
|
|
1026
|
+
if (json == null) {
|
|
1027
|
+
return json;
|
|
1028
|
+
}
|
|
1029
|
+
return {
|
|
1030
|
+
remaining: json["remaining"],
|
|
1031
|
+
reserved: json["reserved"],
|
|
1032
|
+
settled: json["settled"]
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
723
1035
|
var TrialStatus = {
|
|
724
1036
|
Active: "active",
|
|
725
1037
|
Converted: "converted",
|
|
@@ -753,6 +1065,7 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
753
1065
|
return json;
|
|
754
1066
|
}
|
|
755
1067
|
return {
|
|
1068
|
+
creditBalances: json["credit_balances"] == null ? void 0 : mapValues(json["credit_balances"], CompanyCreditBalanceFromJSON),
|
|
756
1069
|
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
757
1070
|
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
758
1071
|
};
|
|
@@ -781,6 +1094,7 @@ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
|
781
1094
|
error: value["error"],
|
|
782
1095
|
flag_id: value["flagId"],
|
|
783
1096
|
flag_key: value["flagKey"],
|
|
1097
|
+
preflight: value["preflight"],
|
|
784
1098
|
reason: value["reason"],
|
|
785
1099
|
req_company: value["reqCompany"],
|
|
786
1100
|
req_user: value["reqUser"],
|
|
@@ -835,7 +1149,10 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
835
1149
|
return {
|
|
836
1150
|
featureUsageExceeded,
|
|
837
1151
|
companyId: companyId == null ? void 0 : companyId,
|
|
1152
|
+
creditId: entitlement?.creditId == null ? void 0 : entitlement.creditId,
|
|
838
1153
|
creditRemaining: entitlement?.creditRemaining == null ? void 0 : entitlement.creditRemaining,
|
|
1154
|
+
creditReserved: entitlement?.creditReserved == null ? void 0 : entitlement.creditReserved,
|
|
1155
|
+
creditSettled: entitlement?.creditSettled == null ? void 0 : entitlement.creditSettled,
|
|
839
1156
|
error: error == null ? void 0 : error,
|
|
840
1157
|
featureAllocation: resolvedAllocation == null ? void 0 : resolvedAllocation,
|
|
841
1158
|
featureUsage: resolvedUsage == null ? void 0 : resolvedUsage,
|
|
@@ -861,6 +1178,22 @@ var CheckPlanReturnFromJSON = (json) => {
|
|
|
861
1178
|
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
862
1179
|
};
|
|
863
1180
|
};
|
|
1181
|
+
var CreditBalancesFromJSON = (json) => {
|
|
1182
|
+
if (json == null || typeof json !== "object") {
|
|
1183
|
+
return {};
|
|
1184
|
+
}
|
|
1185
|
+
const balances = {};
|
|
1186
|
+
for (const [creditId, raw] of Object.entries(json)) {
|
|
1187
|
+
if (raw == null || typeof raw !== "object") continue;
|
|
1188
|
+
const { remaining, reserved, settled } = CompanyCreditBalanceFromJSON(raw);
|
|
1189
|
+
if (typeof remaining !== "number" || typeof reserved !== "number" || typeof settled !== "number") {
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1192
|
+
balances[creditId] = { remaining, reserved, settled };
|
|
1193
|
+
}
|
|
1194
|
+
return balances;
|
|
1195
|
+
};
|
|
1196
|
+
var cacheVersion = "bb56e75d";
|
|
864
1197
|
function contextString(context) {
|
|
865
1198
|
const sortedContext = Object.keys(context).reduce((acc, key) => {
|
|
866
1199
|
const sortedKeys = Object.keys(
|
|
@@ -875,143 +1208,688 @@ function contextString(context) {
|
|
|
875
1208
|
}, {});
|
|
876
1209
|
return JSON.stringify(sortedContext);
|
|
877
1210
|
}
|
|
878
|
-
var version = "1.
|
|
879
|
-
var
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
}
|
|
952
|
-
this.additionalHeaders = {
|
|
953
|
-
"X-Schematic-Client-Version": `schematic-js@${version}`,
|
|
954
|
-
...options?.additionalHeaders ?? {}
|
|
955
|
-
};
|
|
956
|
-
if (options?.storage) {
|
|
957
|
-
this.storage = options.storage;
|
|
958
|
-
} else {
|
|
959
|
-
try {
|
|
960
|
-
if (typeof localStorage !== "undefined") {
|
|
961
|
-
this.storage = localStorage;
|
|
962
|
-
}
|
|
963
|
-
} catch {
|
|
1211
|
+
var version = "1.7.0";
|
|
1212
|
+
var models_exports = {};
|
|
1213
|
+
__export2(models_exports, {
|
|
1214
|
+
ApiErrorFromJSON: () => ApiErrorFromJSON,
|
|
1215
|
+
ApiErrorFromJSONTyped: () => ApiErrorFromJSONTyped,
|
|
1216
|
+
ApiErrorToJSON: () => ApiErrorToJSON,
|
|
1217
|
+
ApiErrorToJSONTyped: () => ApiErrorToJSONTyped,
|
|
1218
|
+
CompanyInvoiceResponseDataFromJSON: () => CompanyInvoiceResponseDataFromJSON,
|
|
1219
|
+
CompanyInvoiceResponseDataFromJSONTyped: () => CompanyInvoiceResponseDataFromJSONTyped,
|
|
1220
|
+
CompanyInvoiceResponseDataToJSON: () => CompanyInvoiceResponseDataToJSON,
|
|
1221
|
+
CompanyInvoiceResponseDataToJSONTyped: () => CompanyInvoiceResponseDataToJSONTyped,
|
|
1222
|
+
CompanyInvoicesResponseDataFromJSON: () => CompanyInvoicesResponseDataFromJSON,
|
|
1223
|
+
CompanyInvoicesResponseDataFromJSONTyped: () => CompanyInvoicesResponseDataFromJSONTyped,
|
|
1224
|
+
CompanyInvoicesResponseDataToJSON: () => CompanyInvoicesResponseDataToJSON,
|
|
1225
|
+
CompanyInvoicesResponseDataToJSONTyped: () => CompanyInvoicesResponseDataToJSONTyped,
|
|
1226
|
+
GetCompanyInvoicesParamsFromJSON: () => GetCompanyInvoicesParamsFromJSON,
|
|
1227
|
+
GetCompanyInvoicesParamsFromJSONTyped: () => GetCompanyInvoicesParamsFromJSONTyped,
|
|
1228
|
+
GetCompanyInvoicesParamsToJSON: () => GetCompanyInvoicesParamsToJSON,
|
|
1229
|
+
GetCompanyInvoicesParamsToJSONTyped: () => GetCompanyInvoicesParamsToJSONTyped,
|
|
1230
|
+
GetCompanyInvoicesResponseFromJSON: () => GetCompanyInvoicesResponseFromJSON,
|
|
1231
|
+
GetCompanyInvoicesResponseFromJSONTyped: () => GetCompanyInvoicesResponseFromJSONTyped,
|
|
1232
|
+
GetCompanyInvoicesResponseToJSON: () => GetCompanyInvoicesResponseToJSON,
|
|
1233
|
+
GetCompanyInvoicesResponseToJSONTyped: () => GetCompanyInvoicesResponseToJSONTyped,
|
|
1234
|
+
InvoiceStatus: () => InvoiceStatus,
|
|
1235
|
+
InvoiceStatusFromJSON: () => InvoiceStatusFromJSON,
|
|
1236
|
+
InvoiceStatusFromJSONTyped: () => InvoiceStatusFromJSONTyped,
|
|
1237
|
+
InvoiceStatusToJSON: () => InvoiceStatusToJSON,
|
|
1238
|
+
InvoiceStatusToJSONTyped: () => InvoiceStatusToJSONTyped,
|
|
1239
|
+
instanceOfApiError: () => instanceOfApiError,
|
|
1240
|
+
instanceOfCompanyInvoiceResponseData: () => instanceOfCompanyInvoiceResponseData,
|
|
1241
|
+
instanceOfCompanyInvoicesResponseData: () => instanceOfCompanyInvoicesResponseData,
|
|
1242
|
+
instanceOfGetCompanyInvoicesParams: () => instanceOfGetCompanyInvoicesParams,
|
|
1243
|
+
instanceOfGetCompanyInvoicesResponse: () => instanceOfGetCompanyInvoicesResponse,
|
|
1244
|
+
instanceOfInvoiceStatus: () => instanceOfInvoiceStatus
|
|
1245
|
+
});
|
|
1246
|
+
function instanceOfApiError(value) {
|
|
1247
|
+
if (!("error" in value) || value["error"] === void 0) return false;
|
|
1248
|
+
return true;
|
|
1249
|
+
}
|
|
1250
|
+
function ApiErrorFromJSON(json) {
|
|
1251
|
+
return ApiErrorFromJSONTyped(json, false);
|
|
1252
|
+
}
|
|
1253
|
+
function ApiErrorFromJSONTyped(json, ignoreDiscriminator) {
|
|
1254
|
+
if (json == null) {
|
|
1255
|
+
return json;
|
|
1256
|
+
}
|
|
1257
|
+
return {
|
|
1258
|
+
error: json["error"]
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
function ApiErrorToJSON(json) {
|
|
1262
|
+
return ApiErrorToJSONTyped(json, false);
|
|
1263
|
+
}
|
|
1264
|
+
function ApiErrorToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1265
|
+
if (value == null) {
|
|
1266
|
+
return value;
|
|
1267
|
+
}
|
|
1268
|
+
return {
|
|
1269
|
+
error: value["error"]
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
var InvoiceStatus = {
|
|
1273
|
+
Draft: "draft",
|
|
1274
|
+
Open: "open",
|
|
1275
|
+
Paid: "paid",
|
|
1276
|
+
Uncollectible: "uncollectible",
|
|
1277
|
+
Void: "void"
|
|
1278
|
+
};
|
|
1279
|
+
function instanceOfInvoiceStatus(value) {
|
|
1280
|
+
for (const key in InvoiceStatus) {
|
|
1281
|
+
if (Object.prototype.hasOwnProperty.call(InvoiceStatus, key)) {
|
|
1282
|
+
if (InvoiceStatus[key] === value) {
|
|
1283
|
+
return true;
|
|
964
1284
|
}
|
|
965
1285
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1286
|
+
}
|
|
1287
|
+
return false;
|
|
1288
|
+
}
|
|
1289
|
+
function InvoiceStatusFromJSON(json) {
|
|
1290
|
+
return InvoiceStatusFromJSONTyped(json, false);
|
|
1291
|
+
}
|
|
1292
|
+
function InvoiceStatusFromJSONTyped(json, ignoreDiscriminator) {
|
|
1293
|
+
return json;
|
|
1294
|
+
}
|
|
1295
|
+
function InvoiceStatusToJSON(value) {
|
|
1296
|
+
return value;
|
|
1297
|
+
}
|
|
1298
|
+
function InvoiceStatusToJSONTyped(value, ignoreDiscriminator) {
|
|
1299
|
+
return value;
|
|
1300
|
+
}
|
|
1301
|
+
function instanceOfCompanyInvoiceResponseData(value) {
|
|
1302
|
+
if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
|
|
1303
|
+
if (!("createdAt" in value) || value["createdAt"] === void 0) return false;
|
|
1304
|
+
if (!("currency" in value) || value["currency"] === void 0) return false;
|
|
1305
|
+
if (!("id" in value) || value["id"] === void 0) return false;
|
|
1306
|
+
return true;
|
|
1307
|
+
}
|
|
1308
|
+
function CompanyInvoiceResponseDataFromJSON(json) {
|
|
1309
|
+
return CompanyInvoiceResponseDataFromJSONTyped(json, false);
|
|
1310
|
+
}
|
|
1311
|
+
function CompanyInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
1312
|
+
if (json == null) {
|
|
1313
|
+
return json;
|
|
1314
|
+
}
|
|
1315
|
+
return {
|
|
1316
|
+
amountDue: json["amount_due"],
|
|
1317
|
+
createdAt: new Date(json["created_at"]),
|
|
1318
|
+
currency: json["currency"],
|
|
1319
|
+
dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
|
|
1320
|
+
id: json["id"],
|
|
1321
|
+
status: json["status"] == null ? void 0 : InvoiceStatusFromJSON(json["status"]),
|
|
1322
|
+
url: json["url"] == null ? void 0 : json["url"]
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function CompanyInvoiceResponseDataToJSON(json) {
|
|
1326
|
+
return CompanyInvoiceResponseDataToJSONTyped(json, false);
|
|
1327
|
+
}
|
|
1328
|
+
function CompanyInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1329
|
+
if (value == null) {
|
|
1330
|
+
return value;
|
|
1331
|
+
}
|
|
1332
|
+
return {
|
|
1333
|
+
amount_due: value["amountDue"],
|
|
1334
|
+
created_at: value["createdAt"].toISOString(),
|
|
1335
|
+
currency: value["currency"],
|
|
1336
|
+
due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
|
|
1337
|
+
id: value["id"],
|
|
1338
|
+
status: InvoiceStatusToJSON(value["status"]),
|
|
1339
|
+
url: value["url"]
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
function instanceOfCompanyInvoicesResponseData(value) {
|
|
1343
|
+
if (!("count" in value) || value["count"] === void 0) return false;
|
|
1344
|
+
if (!("invoices" in value) || value["invoices"] === void 0) return false;
|
|
1345
|
+
return true;
|
|
1346
|
+
}
|
|
1347
|
+
function CompanyInvoicesResponseDataFromJSON(json) {
|
|
1348
|
+
return CompanyInvoicesResponseDataFromJSONTyped(json, false);
|
|
1349
|
+
}
|
|
1350
|
+
function CompanyInvoicesResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
1351
|
+
if (json == null) {
|
|
1352
|
+
return json;
|
|
1353
|
+
}
|
|
1354
|
+
return {
|
|
1355
|
+
count: json["count"],
|
|
1356
|
+
invoices: json["invoices"].map(
|
|
1357
|
+
CompanyInvoiceResponseDataFromJSON
|
|
1358
|
+
)
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
function CompanyInvoicesResponseDataToJSON(json) {
|
|
1362
|
+
return CompanyInvoicesResponseDataToJSONTyped(json, false);
|
|
1363
|
+
}
|
|
1364
|
+
function CompanyInvoicesResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1365
|
+
if (value == null) {
|
|
1366
|
+
return value;
|
|
1367
|
+
}
|
|
1368
|
+
return {
|
|
1369
|
+
count: value["count"],
|
|
1370
|
+
invoices: value["invoices"].map(
|
|
1371
|
+
CompanyInvoiceResponseDataToJSON
|
|
1372
|
+
)
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
function instanceOfGetCompanyInvoicesParams(value) {
|
|
1376
|
+
return true;
|
|
1377
|
+
}
|
|
1378
|
+
function GetCompanyInvoicesParamsFromJSON(json) {
|
|
1379
|
+
return GetCompanyInvoicesParamsFromJSONTyped(json, false);
|
|
1380
|
+
}
|
|
1381
|
+
function GetCompanyInvoicesParamsFromJSONTyped(json, ignoreDiscriminator) {
|
|
1382
|
+
if (json == null) {
|
|
1383
|
+
return json;
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
includePending: json["include_pending"] == null ? void 0 : json["include_pending"],
|
|
1387
|
+
limit: json["limit"] == null ? void 0 : json["limit"],
|
|
1388
|
+
offset: json["offset"] == null ? void 0 : json["offset"]
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
function GetCompanyInvoicesParamsToJSON(json) {
|
|
1392
|
+
return GetCompanyInvoicesParamsToJSONTyped(json, false);
|
|
1393
|
+
}
|
|
1394
|
+
function GetCompanyInvoicesParamsToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1395
|
+
if (value == null) {
|
|
1396
|
+
return value;
|
|
1397
|
+
}
|
|
1398
|
+
return {
|
|
1399
|
+
include_pending: value["includePending"],
|
|
1400
|
+
limit: value["limit"],
|
|
1401
|
+
offset: value["offset"]
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
function instanceOfGetCompanyInvoicesResponse(value) {
|
|
1405
|
+
if (!("data" in value) || value["data"] === void 0) return false;
|
|
1406
|
+
if (!("params" in value) || value["params"] === void 0) return false;
|
|
1407
|
+
return true;
|
|
1408
|
+
}
|
|
1409
|
+
function GetCompanyInvoicesResponseFromJSON(json) {
|
|
1410
|
+
return GetCompanyInvoicesResponseFromJSONTyped(json, false);
|
|
1411
|
+
}
|
|
1412
|
+
function GetCompanyInvoicesResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
1413
|
+
if (json == null) {
|
|
1414
|
+
return json;
|
|
1415
|
+
}
|
|
1416
|
+
return {
|
|
1417
|
+
data: CompanyInvoicesResponseDataFromJSON(json["data"]),
|
|
1418
|
+
params: GetCompanyInvoicesParamsFromJSON(json["params"])
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
function GetCompanyInvoicesResponseToJSON(json) {
|
|
1422
|
+
return GetCompanyInvoicesResponseToJSONTyped(json, false);
|
|
1423
|
+
}
|
|
1424
|
+
function GetCompanyInvoicesResponseToJSONTyped(value, ignoreDiscriminator = false) {
|
|
1425
|
+
if (value == null) {
|
|
1426
|
+
return value;
|
|
1427
|
+
}
|
|
1428
|
+
return {
|
|
1429
|
+
data: CompanyInvoicesResponseDataToJSON(value["data"]),
|
|
1430
|
+
params: GetCompanyInvoicesParamsToJSON(value["params"])
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
var DEFAULT_INVOICE_QUERY = {};
|
|
1434
|
+
function normalizeInvoiceQuery(query) {
|
|
1435
|
+
const { includePending, ...rest } = query;
|
|
1436
|
+
return includePending === true ? { ...rest, includePending: true } : rest;
|
|
1437
|
+
}
|
|
1438
|
+
var SchematicApiError = class extends Error {
|
|
1439
|
+
constructor(status, path, body) {
|
|
1440
|
+
super(
|
|
1441
|
+
typeof body === "object" && body !== null && "error" in body ? String(body.error) : `Request to ${path} failed with status ${status}`
|
|
1442
|
+
);
|
|
1443
|
+
this.status = status;
|
|
1444
|
+
this.path = path;
|
|
1445
|
+
this.body = body;
|
|
1446
|
+
this.name = "SchematicApiError";
|
|
1447
|
+
}
|
|
1448
|
+
status;
|
|
1449
|
+
path;
|
|
1450
|
+
body;
|
|
1451
|
+
};
|
|
1452
|
+
var DEFAULT_API_URL = "https://api.schematichq.com";
|
|
1453
|
+
var TOKEN_CACHE_SIZE = 10;
|
|
1454
|
+
function sessionKey(session) {
|
|
1455
|
+
return JSON.stringify([session.company, session.user ?? null]);
|
|
1456
|
+
}
|
|
1457
|
+
var SchematicSession = class {
|
|
1458
|
+
_apiUrl;
|
|
1459
|
+
_headers;
|
|
1460
|
+
_fetch;
|
|
1461
|
+
_session;
|
|
1462
|
+
_tokens = /* @__PURE__ */ new Map();
|
|
1463
|
+
_resolving = /* @__PURE__ */ new Map();
|
|
1464
|
+
/**
|
|
1465
|
+
* Bumped when the session's identity changes, and only then — the object
|
|
1466
|
+
* itself is replaced on every render. Anything asking "is this still the
|
|
1467
|
+
* session I started under?" counts generations rather than comparing.
|
|
1468
|
+
*/
|
|
1469
|
+
_generation = 0;
|
|
1470
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
1471
|
+
constructor(options = {}) {
|
|
1472
|
+
this._session = options.session;
|
|
1473
|
+
this._apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
1474
|
+
this._headers = options.additionalHeaders ?? {};
|
|
1475
|
+
this._fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
1476
|
+
}
|
|
1477
|
+
get key() {
|
|
1478
|
+
return this._session === null || this._session === void 0 ? void 0 : sessionKey(this._session);
|
|
1479
|
+
}
|
|
1480
|
+
get status() {
|
|
1481
|
+
if (this._session === void 0) {
|
|
1482
|
+
return "pending";
|
|
1483
|
+
}
|
|
1484
|
+
return this._session === null ? "ended" : "active";
|
|
1485
|
+
}
|
|
1486
|
+
/** Only a statement that changes which pair is read counts as a change. */
|
|
1487
|
+
set(session) {
|
|
1488
|
+
if (session === void 0) {
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
const previous = this._session;
|
|
1492
|
+
this._session = session;
|
|
1493
|
+
if (session === null) {
|
|
1494
|
+
if (previous === null) {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
this._tokens.clear();
|
|
1498
|
+
this._resolving.clear();
|
|
1499
|
+
this._generation += 1;
|
|
1500
|
+
this._emit({ type: "ended" });
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
if (previous !== null && previous !== void 0) {
|
|
1504
|
+
if (previous.company === session.company && (previous.user ?? null) === (session.user ?? null)) {
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
this._generation += 1;
|
|
1508
|
+
this._emit({ type: "changed" });
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
this._generation += 1;
|
|
1512
|
+
this._emit({ type: "started" });
|
|
1513
|
+
}
|
|
1514
|
+
onChange(listener) {
|
|
1515
|
+
this._listeners.add(listener);
|
|
1516
|
+
return () => {
|
|
1517
|
+
this._listeners.delete(listener);
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
_emit(event) {
|
|
1521
|
+
for (const listener of this._listeners) {
|
|
1522
|
+
listener(event);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
_cached(key) {
|
|
1526
|
+
const cached = this._tokens.get(key);
|
|
1527
|
+
if (cached === void 0) {
|
|
1528
|
+
return void 0;
|
|
1529
|
+
}
|
|
1530
|
+
if (cached.expiresAt !== void 0 && cached.expiresAt.getTime() <= Date.now()) {
|
|
1531
|
+
this._tokens.delete(key);
|
|
1532
|
+
return void 0;
|
|
1533
|
+
}
|
|
1534
|
+
this._tokens.delete(key);
|
|
1535
|
+
this._tokens.set(key, cached);
|
|
1536
|
+
return cached;
|
|
1537
|
+
}
|
|
1538
|
+
_cache(key, resolved) {
|
|
1539
|
+
this._tokens.delete(key);
|
|
1540
|
+
this._tokens.set(key, resolved);
|
|
1541
|
+
while (this._tokens.size > TOKEN_CACHE_SIZE) {
|
|
1542
|
+
const oldest = this._tokens.keys().next();
|
|
1543
|
+
if (oldest.done === true) {
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
1546
|
+
this._tokens.delete(oldest.value);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* The credential for a session, minted if this one is not held. `force`
|
|
1551
|
+
* retires what is held first: the caller is a request the API has just
|
|
1552
|
+
* rejected.
|
|
1553
|
+
*/
|
|
1554
|
+
resolveToken(session, force) {
|
|
1555
|
+
const { token } = session;
|
|
1556
|
+
if (typeof token === "string") {
|
|
1557
|
+
return Promise.resolve(token);
|
|
1558
|
+
}
|
|
1559
|
+
const key = sessionKey(session);
|
|
1560
|
+
if (!force) {
|
|
1561
|
+
const cached = this._cached(key);
|
|
1562
|
+
if (cached !== void 0) {
|
|
1563
|
+
return Promise.resolve(cached.token);
|
|
1564
|
+
}
|
|
1565
|
+
} else {
|
|
1566
|
+
this._tokens.delete(key);
|
|
1567
|
+
}
|
|
1568
|
+
const inflight = this._resolving.get(key);
|
|
1569
|
+
if (inflight !== void 0 && inflight.sessionGeneration === this._generation && (!force || inflight.forced)) {
|
|
1570
|
+
return inflight.promise;
|
|
1571
|
+
}
|
|
1572
|
+
const provider = token;
|
|
1573
|
+
const sessionGeneration = this._generation;
|
|
1574
|
+
const owns = () => this._resolving.get(key)?.promise === promise;
|
|
1575
|
+
const promise = Promise.resolve().then(() => provider()).then((result) => {
|
|
1576
|
+
const { resolved, stamped } = asResolvedToken(result, session);
|
|
1577
|
+
if (owns() && (this._generation === sessionGeneration || stamped)) {
|
|
1578
|
+
this._cache(key, resolved);
|
|
1579
|
+
}
|
|
1580
|
+
return resolved.token;
|
|
1581
|
+
}).finally(() => {
|
|
1582
|
+
if (owns()) {
|
|
1583
|
+
this._resolving.delete(key);
|
|
1584
|
+
}
|
|
1585
|
+
});
|
|
1586
|
+
this._resolving.set(key, { promise, forced: force, sessionGeneration });
|
|
1587
|
+
return promise;
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Sends a request under the active session's credential, refreshing once
|
|
1591
|
+
* and retrying if the API rejects it. Rejects rather than answering when
|
|
1592
|
+
* the session changes while the request is in flight: the rows would
|
|
1593
|
+
* otherwise come back as the answer to a question asked for another pair.
|
|
1594
|
+
*/
|
|
1595
|
+
async request(path, options = {}) {
|
|
1596
|
+
const { method = "GET", body } = options;
|
|
1597
|
+
const send = async (credential2) => this._fetch(`${this._apiUrl}${path}`, {
|
|
1598
|
+
method,
|
|
1599
|
+
headers: {
|
|
1600
|
+
"Accept": "application/json",
|
|
1601
|
+
...body === void 0 ? {} : { "Content-Type": "application/json" },
|
|
1602
|
+
...this._headers,
|
|
1603
|
+
"X-Schematic-Api-Key": credential2
|
|
1604
|
+
},
|
|
1605
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) }
|
|
1606
|
+
});
|
|
1607
|
+
const session = this._session;
|
|
1608
|
+
if (session === null) {
|
|
1609
|
+
throw new Error("There is no session to read data for.");
|
|
1610
|
+
}
|
|
1611
|
+
if (session === void 0) {
|
|
1612
|
+
throw new Error("A session is required to read data.");
|
|
1613
|
+
}
|
|
1614
|
+
const provider = session.token;
|
|
1615
|
+
const generation = this._generation;
|
|
1616
|
+
const stillOurs = async (response2) => {
|
|
1617
|
+
if (this._generation === generation) {
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
if (response2 !== void 0) {
|
|
1621
|
+
await discardBody(response2);
|
|
1622
|
+
}
|
|
1623
|
+
throw new Error("The session changed while this request was in flight.");
|
|
1624
|
+
};
|
|
1625
|
+
const credential = await this.resolveToken(session, false);
|
|
1626
|
+
if (this._generation !== generation) {
|
|
1627
|
+
throw new Error("The session changed before this request was sent.");
|
|
1628
|
+
}
|
|
1629
|
+
let response = await send(credential);
|
|
1630
|
+
await stillOurs(response);
|
|
1631
|
+
if (response.status === 401 && typeof provider === "function" && this._generation === generation) {
|
|
1632
|
+
const status = response.status;
|
|
1633
|
+
const rejected = await readBody(response);
|
|
1634
|
+
let retried = false;
|
|
1635
|
+
const current = this._session;
|
|
1636
|
+
if (this._generation === generation && current !== null && current !== void 0) {
|
|
1637
|
+
const refreshed = await this.resolveToken(current, true);
|
|
1638
|
+
if (this._generation === generation) {
|
|
1639
|
+
response = await send(refreshed);
|
|
1640
|
+
await stillOurs(response);
|
|
1641
|
+
retried = true;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
if (!retried) {
|
|
1645
|
+
throw new SchematicApiError(status, path, rejected);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
const parsed = await readBody(response);
|
|
1649
|
+
await stillOurs();
|
|
1650
|
+
if (!response.ok) {
|
|
1651
|
+
throw new SchematicApiError(response.status, path, parsed);
|
|
1652
|
+
}
|
|
1653
|
+
return parsed;
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
function asResolvedToken(result, session) {
|
|
1657
|
+
if (typeof result === "string") {
|
|
1658
|
+
return { resolved: { token: result }, stamped: false };
|
|
1659
|
+
}
|
|
1660
|
+
const token = result?.token;
|
|
1661
|
+
if (typeof token !== "string" || token === "") {
|
|
1662
|
+
throw new Error("The access token provider did not return a token.");
|
|
1663
|
+
}
|
|
1664
|
+
if (result.company !== void 0 && result.company !== session.company || result.user !== void 0 && session.user !== void 0 && result.user !== session.user) {
|
|
1665
|
+
throw new Error(
|
|
1666
|
+
"The access token provider returned a token for a different session."
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
const stamped = result.company !== void 0 && (session.user === void 0 || result.user !== void 0);
|
|
1670
|
+
return { resolved: { token, expiresAt: asDate(result.expiresAt) }, stamped };
|
|
1671
|
+
}
|
|
1672
|
+
function asDate(value) {
|
|
1673
|
+
if (value === void 0 || value === null) {
|
|
1674
|
+
return void 0;
|
|
1675
|
+
}
|
|
1676
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
1677
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1678
|
+
}
|
|
1679
|
+
async function discardBody(response) {
|
|
1680
|
+
try {
|
|
1681
|
+
await response.body?.cancel();
|
|
1682
|
+
} catch {
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
async function readBody(response) {
|
|
1686
|
+
const text = await response.text();
|
|
1687
|
+
if (text === "") {
|
|
1688
|
+
return null;
|
|
1689
|
+
}
|
|
1690
|
+
try {
|
|
1691
|
+
return JSON.parse(text);
|
|
1692
|
+
} catch {
|
|
1693
|
+
return text;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
var INVOICE_PAGE_SIZE = 12;
|
|
1697
|
+
var INVOICE_MAX_PAGE_SIZE = 250;
|
|
1698
|
+
var SchematicBillingClient = class {
|
|
1699
|
+
/**
|
|
1700
|
+
* Public so a second client over the same surface can be constructed on
|
|
1701
|
+
* this one rather than minting tokens of its own.
|
|
1702
|
+
*/
|
|
1703
|
+
session;
|
|
1704
|
+
constructor(options = {}) {
|
|
1705
|
+
this.session = options instanceof SchematicSession ? options : new SchematicSession(options);
|
|
1706
|
+
}
|
|
1707
|
+
get sessionKey() {
|
|
1708
|
+
return this.session.key;
|
|
1709
|
+
}
|
|
1710
|
+
get sessionStatus() {
|
|
1711
|
+
return this.session.status;
|
|
1712
|
+
}
|
|
1713
|
+
setSession(session) {
|
|
1714
|
+
this.session.set(session);
|
|
1715
|
+
}
|
|
1716
|
+
onSessionChange(listener) {
|
|
1717
|
+
return this.session.onChange(listener);
|
|
1718
|
+
}
|
|
1719
|
+
fetchInvoices(params) {
|
|
1720
|
+
const query = new URLSearchParams({
|
|
1721
|
+
limit: String(Math.min(params.limit, INVOICE_MAX_PAGE_SIZE)),
|
|
1722
|
+
offset: String(params.offset)
|
|
1723
|
+
});
|
|
1724
|
+
if (params.includePending !== void 0) {
|
|
1725
|
+
query.set("include_pending", String(params.includePending));
|
|
1726
|
+
}
|
|
1727
|
+
const path = `/company/invoices?${query}`;
|
|
1728
|
+
return this.session.request(path).then((body) => {
|
|
1729
|
+
if (body === null || typeof body !== "object" || !("data" in body)) {
|
|
1730
|
+
throw new Error(`Malformed response from ${path}`);
|
|
1731
|
+
}
|
|
1732
|
+
const data = body.data;
|
|
1733
|
+
if (data == null || data.invoices == null) {
|
|
1734
|
+
return { invoices: [], count: 0 };
|
|
1735
|
+
}
|
|
1736
|
+
const decoded = GetCompanyInvoicesResponseFromJSON(body).data;
|
|
1737
|
+
return { invoices: decoded.invoices, count: decoded.count };
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1741
|
+
var anonymousIdKey = "schematicId";
|
|
1742
|
+
var flagStateCachePrefix = "schematicCache";
|
|
1743
|
+
var flagStateCacheMaxContexts = 10;
|
|
1744
|
+
var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
|
|
1745
|
+
var emptyCreditBalances = Object.freeze({});
|
|
1746
|
+
var Schematic = class {
|
|
1747
|
+
_additionalHeaders = {};
|
|
1748
|
+
apiKey;
|
|
1749
|
+
_apiUrl = "https://api.schematichq.com";
|
|
1750
|
+
conn = null;
|
|
1751
|
+
context = {};
|
|
1752
|
+
debugEnabled = false;
|
|
1753
|
+
offlineEnabled = false;
|
|
1754
|
+
eventQueue;
|
|
1755
|
+
contextDependentEventQueue;
|
|
1756
|
+
eventUrl = "https://c.schematichq.com";
|
|
1757
|
+
flagCheckListeners = {};
|
|
1758
|
+
flagValueListeners = {};
|
|
1759
|
+
isPending = true;
|
|
1760
|
+
isPendingListeners = /* @__PURE__ */ new Set();
|
|
1761
|
+
planListeners = /* @__PURE__ */ new Set();
|
|
1762
|
+
creditBalanceListeners = /* @__PURE__ */ new Set();
|
|
1763
|
+
storage;
|
|
1764
|
+
persistFlagState = true;
|
|
1765
|
+
flagStateCacheKey;
|
|
1766
|
+
flagStateCacheMaxAgeMs = flagStateCacheDefaultMaxAgeMs;
|
|
1767
|
+
cachedFlagState = null;
|
|
1768
|
+
useWebSocket = false;
|
|
1769
|
+
checks = {};
|
|
1770
|
+
featureUsageEventMap = {};
|
|
1771
|
+
planChecks = {};
|
|
1772
|
+
creditBalances = {};
|
|
1773
|
+
webSocketUrl = "wss://api.schematichq.com";
|
|
1774
|
+
webSocketConnectionTimeout = 1e4;
|
|
1775
|
+
webSocketReconnect = true;
|
|
1776
|
+
webSocketMaxReconnectAttempts = 7;
|
|
1777
|
+
// Max attempts after connection disrupted
|
|
1778
|
+
webSocketMaxConnectionAttempts = 3;
|
|
1779
|
+
// Max attempts for initial connection
|
|
1780
|
+
webSocketInitialRetryDelay = 1e3;
|
|
1781
|
+
webSocketMaxRetryDelay = 3e4;
|
|
1782
|
+
wsReconnectAttempts = 0;
|
|
1783
|
+
wsReconnectTimer = null;
|
|
1784
|
+
wsIntentionalDisconnect = false;
|
|
1785
|
+
currentWebSocket = null;
|
|
1786
|
+
isConnecting = false;
|
|
1787
|
+
maxEventQueueSize = 100;
|
|
1788
|
+
// Prevent memory issues with very long network outages
|
|
1789
|
+
maxEventRetries = 5;
|
|
1790
|
+
// Maximum retry attempts for failed events
|
|
1791
|
+
eventRetryInitialDelay = 1e3;
|
|
1792
|
+
// Initial retry delay in ms
|
|
1793
|
+
eventRetryMaxDelay = 3e4;
|
|
1794
|
+
// Maximum retry delay in ms
|
|
1795
|
+
retryTimer = null;
|
|
1796
|
+
flagValueDefaults = {};
|
|
1797
|
+
flagCheckDefaults = {};
|
|
1798
|
+
fallbackCheckCache = {};
|
|
1799
|
+
constructor(apiKey, options) {
|
|
1800
|
+
this.apiKey = apiKey;
|
|
1801
|
+
this.flagStateCacheKey = `${flagStateCachePrefix}:${apiKey}`;
|
|
1802
|
+
this.eventQueue = [];
|
|
1803
|
+
this.contextDependentEventQueue = [];
|
|
1804
|
+
this.useWebSocket = options?.useWebSocket ?? false;
|
|
1805
|
+
this.debugEnabled = options?.debug ?? false;
|
|
1806
|
+
this.offlineEnabled = options?.offline ?? false;
|
|
1807
|
+
this.persistFlagState = options?.persistFlagState ?? true;
|
|
1808
|
+
if (typeof options?.flagStateCacheMaxAgeMs === "number" && options.flagStateCacheMaxAgeMs > 0) {
|
|
1809
|
+
this.flagStateCacheMaxAgeMs = options.flagStateCacheMaxAgeMs;
|
|
1810
|
+
}
|
|
1811
|
+
if (typeof window !== "undefined" && typeof window.location !== "undefined") {
|
|
1812
|
+
const params = new URLSearchParams(window.location.search);
|
|
1813
|
+
const debugParam = params.get("schematic_debug");
|
|
1814
|
+
if (debugParam !== null && (debugParam === "" || debugParam === "true" || debugParam === "1")) {
|
|
1815
|
+
this.debugEnabled = true;
|
|
1816
|
+
}
|
|
1817
|
+
const offlineParam = params.get("schematic_offline");
|
|
1818
|
+
if (offlineParam !== null && (offlineParam === "" || offlineParam === "true" || offlineParam === "1")) {
|
|
1819
|
+
this.offlineEnabled = true;
|
|
1820
|
+
this.debugEnabled = true;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
if (this.offlineEnabled && options?.debug !== false) {
|
|
1824
|
+
this.debugEnabled = true;
|
|
1825
|
+
}
|
|
1826
|
+
if (this.offlineEnabled) {
|
|
1827
|
+
this.setIsPending(false);
|
|
1828
|
+
}
|
|
1829
|
+
this._additionalHeaders = {
|
|
1830
|
+
"X-Schematic-Client-Version": `schematic-js@${version}`,
|
|
1831
|
+
...options?.additionalHeaders ?? {}
|
|
1832
|
+
};
|
|
1833
|
+
if (options?.storage) {
|
|
1834
|
+
this.storage = options.storage;
|
|
1835
|
+
} else {
|
|
1836
|
+
try {
|
|
1837
|
+
if (typeof localStorage !== "undefined") {
|
|
1838
|
+
this.storage = localStorage;
|
|
1839
|
+
}
|
|
1840
|
+
} catch {
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
this.hydrateFlagStateFromCache();
|
|
1844
|
+
if (options?.apiUrl !== void 0) {
|
|
1845
|
+
this._apiUrl = options.apiUrl;
|
|
1846
|
+
}
|
|
1847
|
+
if (options?.eventUrl !== void 0) {
|
|
1848
|
+
this.eventUrl = options.eventUrl;
|
|
1849
|
+
}
|
|
1850
|
+
if (options?.webSocketUrl !== void 0) {
|
|
1851
|
+
this.webSocketUrl = options.webSocketUrl;
|
|
1852
|
+
}
|
|
1853
|
+
if (options?.webSocketConnectionTimeout !== void 0) {
|
|
1854
|
+
this.webSocketConnectionTimeout = options.webSocketConnectionTimeout;
|
|
1855
|
+
}
|
|
1856
|
+
if (options?.webSocketReconnect !== void 0) {
|
|
1857
|
+
this.webSocketReconnect = options.webSocketReconnect;
|
|
1858
|
+
}
|
|
1859
|
+
if (options?.webSocketMaxReconnectAttempts !== void 0) {
|
|
1860
|
+
this.webSocketMaxReconnectAttempts = options.webSocketMaxReconnectAttempts;
|
|
1861
|
+
}
|
|
1862
|
+
if (options?.webSocketInitialRetryDelay !== void 0) {
|
|
1863
|
+
this.webSocketInitialRetryDelay = options.webSocketInitialRetryDelay;
|
|
1864
|
+
}
|
|
1865
|
+
if (options?.webSocketMaxRetryDelay !== void 0) {
|
|
1866
|
+
this.webSocketMaxRetryDelay = options.webSocketMaxRetryDelay;
|
|
1867
|
+
}
|
|
1868
|
+
if (options?.maxEventQueueSize !== void 0) {
|
|
1869
|
+
this.maxEventQueueSize = options.maxEventQueueSize;
|
|
1870
|
+
}
|
|
1871
|
+
if (options?.maxEventRetries !== void 0) {
|
|
1872
|
+
this.maxEventRetries = options.maxEventRetries;
|
|
1873
|
+
}
|
|
1874
|
+
if (options?.eventRetryInitialDelay !== void 0) {
|
|
1875
|
+
this.eventRetryInitialDelay = options.eventRetryInitialDelay;
|
|
1876
|
+
}
|
|
1877
|
+
if (options?.eventRetryMaxDelay !== void 0) {
|
|
1878
|
+
this.eventRetryMaxDelay = options.eventRetryMaxDelay;
|
|
1879
|
+
}
|
|
1880
|
+
if (options?.flagValueDefaults !== void 0) {
|
|
1881
|
+
this.flagValueDefaults = options.flagValueDefaults;
|
|
1882
|
+
}
|
|
1883
|
+
if (options?.flagCheckDefaults !== void 0) {
|
|
1884
|
+
this.flagCheckDefaults = options.flagCheckDefaults;
|
|
1885
|
+
}
|
|
1886
|
+
if (typeof window !== "undefined" && window?.addEventListener) {
|
|
1887
|
+
window.addEventListener("beforeunload", () => {
|
|
1888
|
+
this.flushEventQueue();
|
|
1889
|
+
this.flushContextDependentEventQueue();
|
|
1890
|
+
});
|
|
1891
|
+
if (this.useWebSocket) {
|
|
1892
|
+
window.addEventListener("offline", () => {
|
|
1015
1893
|
this.debug("Browser went offline, closing WebSocket connection");
|
|
1016
1894
|
this.handleNetworkOffline();
|
|
1017
1895
|
});
|
|
@@ -1029,6 +1907,12 @@ var Schematic = class {
|
|
|
1029
1907
|
this.debug("Initialized with debug mode enabled");
|
|
1030
1908
|
}
|
|
1031
1909
|
}
|
|
1910
|
+
get apiUrl() {
|
|
1911
|
+
return this._apiUrl;
|
|
1912
|
+
}
|
|
1913
|
+
get additionalHeaders() {
|
|
1914
|
+
return { ...this._additionalHeaders };
|
|
1915
|
+
}
|
|
1032
1916
|
/**
|
|
1033
1917
|
* Resolve fallback value according to priority order:
|
|
1034
1918
|
* 1. Callsite fallback value (if provided)
|
|
@@ -1114,11 +1998,11 @@ var Schematic = class {
|
|
|
1114
1998
|
return resolvedFallbackResult.value;
|
|
1115
1999
|
}
|
|
1116
2000
|
if (!this.useWebSocket) {
|
|
1117
|
-
const requestUrl = `${this.
|
|
2001
|
+
const requestUrl = `${this._apiUrl}/flags/${key}/check`;
|
|
1118
2002
|
return fetch(requestUrl, {
|
|
1119
2003
|
method: "POST",
|
|
1120
2004
|
headers: {
|
|
1121
|
-
...this.
|
|
2005
|
+
...this._additionalHeaders ?? {},
|
|
1122
2006
|
"Content-Type": "application/json;charset=UTF-8",
|
|
1123
2007
|
"X-Schematic-Api-Key": this.apiKey
|
|
1124
2008
|
},
|
|
@@ -1256,6 +2140,29 @@ var Schematic = class {
|
|
|
1256
2140
|
});
|
|
1257
2141
|
this.notifyPlanListeners(plan);
|
|
1258
2142
|
}
|
|
2143
|
+
if (message.credit_balances !== void 0 && message.credit_balances !== null) {
|
|
2144
|
+
const contextStr = contextString(context);
|
|
2145
|
+
const updates = CreditBalancesFromJSON(message.credit_balances);
|
|
2146
|
+
const previous = this.creditBalances[contextStr] ?? {};
|
|
2147
|
+
let changed = false;
|
|
2148
|
+
const merged = { ...previous };
|
|
2149
|
+
for (const [creditId, next] of Object.entries(updates)) {
|
|
2150
|
+
const current = previous[creditId];
|
|
2151
|
+
if (current === void 0 || current.remaining !== next.remaining || current.reserved !== next.reserved || current.settled !== next.settled) {
|
|
2152
|
+
merged[creditId] = next;
|
|
2153
|
+
changed = true;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
if (changed) {
|
|
2157
|
+
this.creditBalances[contextStr] = merged;
|
|
2158
|
+
this.debug(
|
|
2159
|
+
`WebSocket credit balance update received. Notifying listeners`,
|
|
2160
|
+
{ creditBalances: merged }
|
|
2161
|
+
);
|
|
2162
|
+
this.notifyCreditBalanceListeners(merged);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
this.persistContextToCache(contextString(context));
|
|
1259
2166
|
this.flushContextDependentEventQueue();
|
|
1260
2167
|
this.setIsPending(false);
|
|
1261
2168
|
};
|
|
@@ -1298,12 +2205,12 @@ var Schematic = class {
|
|
|
1298
2205
|
this.debug(`checkFlags offline result: returning empty object`);
|
|
1299
2206
|
return {};
|
|
1300
2207
|
}
|
|
1301
|
-
const requestUrl = `${this.
|
|
2208
|
+
const requestUrl = `${this._apiUrl}/flags/check`;
|
|
1302
2209
|
const requestBody = JSON.stringify(context);
|
|
1303
2210
|
return fetch(requestUrl, {
|
|
1304
2211
|
method: "POST",
|
|
1305
2212
|
headers: {
|
|
1306
|
-
...this.
|
|
2213
|
+
...this._additionalHeaders ?? {},
|
|
1307
2214
|
"Content-Type": "application/json;charset=UTF-8",
|
|
1308
2215
|
"X-Schematic-Api-Key": this.apiKey
|
|
1309
2216
|
},
|
|
@@ -1363,7 +2270,32 @@ var Schematic = class {
|
|
|
1363
2270
|
return;
|
|
1364
2271
|
}
|
|
1365
2272
|
try {
|
|
1366
|
-
|
|
2273
|
+
const newContextStr = contextString(context);
|
|
2274
|
+
const cacheHit = this.hasCachedValuesForContext(newContextStr);
|
|
2275
|
+
if (cacheHit) {
|
|
2276
|
+
this.debug(
|
|
2277
|
+
`setContext: cache hit for context, pre-resolving from cached values`
|
|
2278
|
+
);
|
|
2279
|
+
this.context = context;
|
|
2280
|
+
this.flushContextDependentEventQueue();
|
|
2281
|
+
this.setIsPending(false);
|
|
2282
|
+
const cachedChecks = this.checks[newContextStr] ?? {};
|
|
2283
|
+
for (const [flagKey, check] of Object.entries(cachedChecks)) {
|
|
2284
|
+
if (check === void 0) continue;
|
|
2285
|
+
this.notifyFlagCheckListeners(flagKey, check);
|
|
2286
|
+
this.notifyFlagValueListeners(flagKey, check.value);
|
|
2287
|
+
}
|
|
2288
|
+
const cachedPlan = this.planChecks[newContextStr];
|
|
2289
|
+
if (cachedPlan !== void 0) {
|
|
2290
|
+
this.notifyPlanListeners(cachedPlan);
|
|
2291
|
+
}
|
|
2292
|
+
const cachedCreditBalances = this.creditBalances[newContextStr];
|
|
2293
|
+
if (cachedCreditBalances !== void 0) {
|
|
2294
|
+
this.notifyCreditBalanceListeners(cachedCreditBalances);
|
|
2295
|
+
}
|
|
2296
|
+
} else {
|
|
2297
|
+
this.setIsPending(true);
|
|
2298
|
+
}
|
|
1367
2299
|
if (!this.conn) {
|
|
1368
2300
|
if (this.isConnecting) {
|
|
1369
2301
|
this.debug(
|
|
@@ -1374,7 +2306,7 @@ var Schematic = class {
|
|
|
1374
2306
|
}
|
|
1375
2307
|
if (this.conn !== null) {
|
|
1376
2308
|
const socket2 = await this.conn;
|
|
1377
|
-
await this.wsSendMessage(socket2, context);
|
|
2309
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1378
2310
|
return;
|
|
1379
2311
|
}
|
|
1380
2312
|
}
|
|
@@ -1390,7 +2322,7 @@ var Schematic = class {
|
|
|
1390
2322
|
this.conn = this.wsConnect();
|
|
1391
2323
|
const socket2 = await this.conn;
|
|
1392
2324
|
this.isConnecting = false;
|
|
1393
|
-
await this.wsSendMessage(socket2, context);
|
|
2325
|
+
await this.wsSendMessage(socket2, context, cacheHit);
|
|
1394
2326
|
return;
|
|
1395
2327
|
} catch (error) {
|
|
1396
2328
|
this.isConnecting = false;
|
|
@@ -1398,7 +2330,7 @@ var Schematic = class {
|
|
|
1398
2330
|
}
|
|
1399
2331
|
}
|
|
1400
2332
|
const socket = await this.conn;
|
|
1401
|
-
await this.wsSendMessage(socket, context);
|
|
2333
|
+
await this.wsSendMessage(socket, context, cacheHit);
|
|
1402
2334
|
} catch (error) {
|
|
1403
2335
|
console.warn("Failed to establish WebSocket connection:", error);
|
|
1404
2336
|
this.context = context;
|
|
@@ -1458,10 +2390,12 @@ var Schematic = class {
|
|
|
1458
2390
|
`Optimistically updating feature usage for event: ${eventName}`,
|
|
1459
2391
|
{ quantity }
|
|
1460
2392
|
);
|
|
2393
|
+
let dirty = false;
|
|
1461
2394
|
Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
|
|
1462
2395
|
if (check === void 0) return;
|
|
1463
2396
|
const updatedCheck = { ...check };
|
|
1464
2397
|
if (typeof updatedCheck.featureUsage === "number") {
|
|
2398
|
+
dirty = true;
|
|
1465
2399
|
updatedCheck.featureUsage += quantity;
|
|
1466
2400
|
if (typeof updatedCheck.featureAllocation === "number") {
|
|
1467
2401
|
const wasExceeded = updatedCheck.featureUsageExceeded === true;
|
|
@@ -1491,6 +2425,9 @@ var Schematic = class {
|
|
|
1491
2425
|
this.notifyFlagValueListeners(flagKey, updatedCheck.value);
|
|
1492
2426
|
}
|
|
1493
2427
|
});
|
|
2428
|
+
if (dirty) {
|
|
2429
|
+
this.persistContextToCache(contextString(this.context));
|
|
2430
|
+
}
|
|
1494
2431
|
};
|
|
1495
2432
|
/**
|
|
1496
2433
|
* Event processing
|
|
@@ -1593,6 +2530,206 @@ var Schematic = class {
|
|
|
1593
2530
|
this.storage.setItem(anonymousIdKey, generatedAnonymousId);
|
|
1594
2531
|
return generatedAnonymousId;
|
|
1595
2532
|
};
|
|
2533
|
+
hasCachedValuesForContext = (contextStr) => {
|
|
2534
|
+
const cachedChecks = this.checks[contextStr];
|
|
2535
|
+
if (cachedChecks !== void 0 && Object.keys(cachedChecks).length > 0) {
|
|
2536
|
+
return true;
|
|
2537
|
+
}
|
|
2538
|
+
if (this.planChecks[contextStr] !== void 0) {
|
|
2539
|
+
return true;
|
|
2540
|
+
}
|
|
2541
|
+
const cachedCreditBalances = this.creditBalances[contextStr];
|
|
2542
|
+
return cachedCreditBalances !== void 0 && Object.keys(cachedCreditBalances).length > 0;
|
|
2543
|
+
};
|
|
2544
|
+
readFlagStateCache = () => {
|
|
2545
|
+
if (!this.persistFlagState || this.storage === void 0) {
|
|
2546
|
+
return null;
|
|
2547
|
+
}
|
|
2548
|
+
let raw;
|
|
2549
|
+
try {
|
|
2550
|
+
raw = this.storage.getItem(this.flagStateCacheKey);
|
|
2551
|
+
} catch (error) {
|
|
2552
|
+
this.debug("Failed to read flag state cache:", error);
|
|
2553
|
+
return null;
|
|
2554
|
+
}
|
|
2555
|
+
if (raw === null || raw === void 0) {
|
|
2556
|
+
return null;
|
|
2557
|
+
}
|
|
2558
|
+
let parsed;
|
|
2559
|
+
try {
|
|
2560
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
2561
|
+
} catch (error) {
|
|
2562
|
+
this.debug("Flag state cache is not valid JSON, ignoring:", error);
|
|
2563
|
+
return null;
|
|
2564
|
+
}
|
|
2565
|
+
if (parsed === null || typeof parsed !== "object" || parsed.version !== cacheVersion || typeof parsed.contexts !== "object" || parsed.contexts === null) {
|
|
2566
|
+
this.debug(
|
|
2567
|
+
`Flag state cache invalid or version mismatch (expected ${cacheVersion}), ignoring`,
|
|
2568
|
+
{
|
|
2569
|
+
parsedType: typeof parsed,
|
|
2570
|
+
version: parsed?.version
|
|
2571
|
+
}
|
|
2572
|
+
);
|
|
2573
|
+
return null;
|
|
2574
|
+
}
|
|
2575
|
+
return parsed;
|
|
2576
|
+
};
|
|
2577
|
+
reviveCachedCheck = (raw) => {
|
|
2578
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2579
|
+
const obj = raw;
|
|
2580
|
+
if (typeof obj.flag !== "string" || typeof obj.value !== "boolean" || typeof obj.reason !== "string") {
|
|
2581
|
+
return null;
|
|
2582
|
+
}
|
|
2583
|
+
const revived = { ...obj };
|
|
2584
|
+
if (typeof revived.featureUsageResetAt === "string") {
|
|
2585
|
+
const d = new Date(revived.featureUsageResetAt);
|
|
2586
|
+
revived.featureUsageResetAt = isNaN(d.getTime()) ? void 0 : d;
|
|
2587
|
+
}
|
|
2588
|
+
return revived;
|
|
2589
|
+
};
|
|
2590
|
+
reviveCachedPlan = (raw) => {
|
|
2591
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2592
|
+
const obj = raw;
|
|
2593
|
+
if (typeof obj.id !== "string" || typeof obj.name !== "string") {
|
|
2594
|
+
return null;
|
|
2595
|
+
}
|
|
2596
|
+
const revived = { ...obj };
|
|
2597
|
+
if (typeof revived.trialEndDate === "string") {
|
|
2598
|
+
const d = new Date(revived.trialEndDate);
|
|
2599
|
+
revived.trialEndDate = isNaN(d.getTime()) ? void 0 : d;
|
|
2600
|
+
}
|
|
2601
|
+
return revived;
|
|
2602
|
+
};
|
|
2603
|
+
reviveCachedCreditBalances = (raw) => {
|
|
2604
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
2605
|
+
const revived = {};
|
|
2606
|
+
for (const [creditId, value] of Object.entries(
|
|
2607
|
+
raw
|
|
2608
|
+
)) {
|
|
2609
|
+
if (value === null || typeof value !== "object") continue;
|
|
2610
|
+
const obj = value;
|
|
2611
|
+
if (typeof obj.remaining !== "number" || typeof obj.reserved !== "number" || typeof obj.settled !== "number") {
|
|
2612
|
+
continue;
|
|
2613
|
+
}
|
|
2614
|
+
revived[creditId] = {
|
|
2615
|
+
remaining: obj.remaining,
|
|
2616
|
+
reserved: obj.reserved,
|
|
2617
|
+
settled: obj.settled
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
return Object.keys(revived).length > 0 ? revived : null;
|
|
2621
|
+
};
|
|
2622
|
+
hydrateFlagStateFromCache = () => {
|
|
2623
|
+
const parsed = this.readFlagStateCache();
|
|
2624
|
+
if (parsed === null) return;
|
|
2625
|
+
const cutoff = Date.now() - this.flagStateCacheMaxAgeMs;
|
|
2626
|
+
const fresh = {};
|
|
2627
|
+
let contextsLoaded = 0;
|
|
2628
|
+
let contextsExpired = 0;
|
|
2629
|
+
for (const [contextStr, entry] of Object.entries(parsed.contexts)) {
|
|
2630
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2631
|
+
if (typeof entry.updatedAt !== "number") continue;
|
|
2632
|
+
if (entry.updatedAt < cutoff) {
|
|
2633
|
+
contextsExpired += 1;
|
|
2634
|
+
continue;
|
|
2635
|
+
}
|
|
2636
|
+
const revivedChecks = {};
|
|
2637
|
+
if (entry.checks !== null && typeof entry.checks === "object") {
|
|
2638
|
+
for (const [flagKey, rawCheck] of Object.entries(entry.checks)) {
|
|
2639
|
+
const revived = this.reviveCachedCheck(rawCheck);
|
|
2640
|
+
if (revived === null || revived.flag !== flagKey) continue;
|
|
2641
|
+
revivedChecks[flagKey] = revived;
|
|
2642
|
+
if (typeof revived.featureUsageEvent === "string") {
|
|
2643
|
+
this.updateFeatureUsageEventMap(revived);
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
if (Object.keys(revivedChecks).length > 0) {
|
|
2647
|
+
this.checks[contextStr] = revivedChecks;
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
let revivedPlan;
|
|
2651
|
+
if (entry.plan !== void 0 && entry.plan !== null) {
|
|
2652
|
+
const p = this.reviveCachedPlan(entry.plan);
|
|
2653
|
+
if (p !== null) {
|
|
2654
|
+
revivedPlan = p;
|
|
2655
|
+
this.planChecks[contextStr] = p;
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
let revivedCreditBalances;
|
|
2659
|
+
if (entry.creditBalances !== void 0 && entry.creditBalances !== null) {
|
|
2660
|
+
const balances = this.reviveCachedCreditBalances(entry.creditBalances);
|
|
2661
|
+
if (balances !== null) {
|
|
2662
|
+
revivedCreditBalances = balances;
|
|
2663
|
+
this.creditBalances[contextStr] = balances;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
fresh[contextStr] = {
|
|
2667
|
+
checks: revivedChecks,
|
|
2668
|
+
plan: revivedPlan,
|
|
2669
|
+
creditBalances: revivedCreditBalances,
|
|
2670
|
+
updatedAt: entry.updatedAt
|
|
2671
|
+
};
|
|
2672
|
+
contextsLoaded += 1;
|
|
2673
|
+
}
|
|
2674
|
+
this.cachedFlagState = { version: cacheVersion, contexts: fresh };
|
|
2675
|
+
this.debug(
|
|
2676
|
+
`Hydrated flag state cache: ${contextsLoaded} loaded, ${contextsExpired} expired`
|
|
2677
|
+
);
|
|
2678
|
+
};
|
|
2679
|
+
persistContextToCache = (contextStr) => {
|
|
2680
|
+
const checksForContext = this.checks[contextStr];
|
|
2681
|
+
const planForContext = this.planChecks[contextStr];
|
|
2682
|
+
const creditBalancesForContext = this.creditBalances[contextStr];
|
|
2683
|
+
if (checksForContext === void 0 && planForContext === void 0 && creditBalancesForContext === void 0) {
|
|
2684
|
+
return;
|
|
2685
|
+
}
|
|
2686
|
+
if (this.cachedFlagState === null) {
|
|
2687
|
+
this.cachedFlagState = (this.persistFlagState ? this.readFlagStateCache() : null) ?? {
|
|
2688
|
+
version: cacheVersion,
|
|
2689
|
+
contexts: {}
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
const cleanChecks = {};
|
|
2693
|
+
if (checksForContext !== void 0) {
|
|
2694
|
+
for (const [flagKey, check] of Object.entries(checksForContext)) {
|
|
2695
|
+
if (check !== void 0) cleanChecks[flagKey] = check;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
this.cachedFlagState.contexts[contextStr] = {
|
|
2699
|
+
checks: cleanChecks,
|
|
2700
|
+
plan: planForContext,
|
|
2701
|
+
creditBalances: creditBalancesForContext,
|
|
2702
|
+
updatedAt: Date.now()
|
|
2703
|
+
};
|
|
2704
|
+
const entries = Object.entries(this.cachedFlagState.contexts);
|
|
2705
|
+
if (entries.length > flagStateCacheMaxContexts) {
|
|
2706
|
+
entries.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
|
2707
|
+
const survivors = entries.slice(0, flagStateCacheMaxContexts);
|
|
2708
|
+
const survivorKeys = new Set(survivors.map(([k]) => k));
|
|
2709
|
+
for (const key of Object.keys(this.checks)) {
|
|
2710
|
+
if (!survivorKeys.has(key)) delete this.checks[key];
|
|
2711
|
+
}
|
|
2712
|
+
for (const key of Object.keys(this.planChecks)) {
|
|
2713
|
+
if (!survivorKeys.has(key)) delete this.planChecks[key];
|
|
2714
|
+
}
|
|
2715
|
+
for (const key of Object.keys(this.creditBalances)) {
|
|
2716
|
+
if (!survivorKeys.has(key)) delete this.creditBalances[key];
|
|
2717
|
+
}
|
|
2718
|
+
this.cachedFlagState = {
|
|
2719
|
+
version: cacheVersion,
|
|
2720
|
+
contexts: Object.fromEntries(survivors)
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
if (!this.persistFlagState || this.storage === void 0) return;
|
|
2724
|
+
try {
|
|
2725
|
+
this.storage.setItem(
|
|
2726
|
+
this.flagStateCacheKey,
|
|
2727
|
+
JSON.stringify(this.cachedFlagState)
|
|
2728
|
+
);
|
|
2729
|
+
} catch (error) {
|
|
2730
|
+
this.debug("Failed to write flag state cache:", error);
|
|
2731
|
+
}
|
|
2732
|
+
};
|
|
1596
2733
|
handleEvent = (eventType, eventBody) => {
|
|
1597
2734
|
const event = {
|
|
1598
2735
|
api_key: this.apiKey,
|
|
@@ -1620,7 +2757,7 @@ var Schematic = class {
|
|
|
1620
2757
|
const response = await fetch(captureUrl, {
|
|
1621
2758
|
method: "POST",
|
|
1622
2759
|
headers: {
|
|
1623
|
-
...this.
|
|
2760
|
+
...this._additionalHeaders ?? {},
|
|
1624
2761
|
"Content-Type": "application/json;charset=UTF-8"
|
|
1625
2762
|
},
|
|
1626
2763
|
body: payload
|
|
@@ -1853,6 +2990,9 @@ var Schematic = class {
|
|
|
1853
2990
|
if (this.conn !== null) {
|
|
1854
2991
|
try {
|
|
1855
2992
|
const socket = await this.conn;
|
|
2993
|
+
if (this.currentWebSocket === socket) {
|
|
2994
|
+
this.currentWebSocket = null;
|
|
2995
|
+
}
|
|
1856
2996
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
1857
2997
|
socket.close();
|
|
1858
2998
|
}
|
|
@@ -2018,6 +3158,7 @@ var Schematic = class {
|
|
|
2018
3158
|
this.debug(`Creating WebSocket connection ${connectionId} to ${wsUrl}`);
|
|
2019
3159
|
let timeoutId = null;
|
|
2020
3160
|
let isResolved = false;
|
|
3161
|
+
let didOpen = false;
|
|
2021
3162
|
timeoutId = setTimeout(() => {
|
|
2022
3163
|
if (!isResolved) {
|
|
2023
3164
|
isResolved = true;
|
|
@@ -2031,6 +3172,7 @@ var Schematic = class {
|
|
|
2031
3172
|
webSocket.onopen = () => {
|
|
2032
3173
|
if (isResolved) return;
|
|
2033
3174
|
isResolved = true;
|
|
3175
|
+
didOpen = true;
|
|
2034
3176
|
if (timeoutId !== null) {
|
|
2035
3177
|
clearTimeout(timeoutId);
|
|
2036
3178
|
}
|
|
@@ -2056,11 +3198,12 @@ var Schematic = class {
|
|
|
2056
3198
|
}
|
|
2057
3199
|
this.debug(`WebSocket connection ${connectionId} closed`);
|
|
2058
3200
|
this.conn = null;
|
|
3201
|
+
const wasCurrent = this.currentWebSocket === webSocket;
|
|
2059
3202
|
if (this.currentWebSocket === webSocket) {
|
|
2060
3203
|
this.currentWebSocket = null;
|
|
2061
3204
|
this.isConnecting = false;
|
|
2062
3205
|
}
|
|
2063
|
-
if (
|
|
3206
|
+
if (wasCurrent && didOpen && !this.wsIntentionalDisconnect && this.webSocketReconnect) {
|
|
2064
3207
|
this.attemptReconnect();
|
|
2065
3208
|
}
|
|
2066
3209
|
};
|
|
@@ -2110,7 +3253,7 @@ var Schematic = class {
|
|
|
2110
3253
|
}
|
|
2111
3254
|
});
|
|
2112
3255
|
this.currentWebSocket = socket;
|
|
2113
|
-
const clientVersion = this.
|
|
3256
|
+
const clientVersion = this._additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
|
|
2114
3257
|
const messagePayload = {
|
|
2115
3258
|
apiKey: this.apiKey,
|
|
2116
3259
|
clientVersion,
|
|
@@ -2156,6 +3299,16 @@ var Schematic = class {
|
|
|
2156
3299
|
const plan = this.planChecks[contextStr];
|
|
2157
3300
|
return plan;
|
|
2158
3301
|
};
|
|
3302
|
+
/** Get the company's lease-aware credit balances for the current context, keyed by credit ID */
|
|
3303
|
+
getCreditBalances = () => {
|
|
3304
|
+
const contextStr = contextString(this.context);
|
|
3305
|
+
return this.creditBalances[contextStr] ?? emptyCreditBalances;
|
|
3306
|
+
};
|
|
3307
|
+
/** Get the company's lease-aware balance for a single credit type in the current context */
|
|
3308
|
+
getCreditBalance = (creditId) => {
|
|
3309
|
+
const contextStr = contextString(this.context);
|
|
3310
|
+
return this.creditBalances[contextStr]?.[creditId];
|
|
3311
|
+
};
|
|
2159
3312
|
// flag checks state
|
|
2160
3313
|
getFlagCheck = (flagKey) => {
|
|
2161
3314
|
const contextStr = contextString(this.context);
|
|
@@ -2215,6 +3368,13 @@ var Schematic = class {
|
|
|
2215
3368
|
this.planListeners.delete(listener);
|
|
2216
3369
|
};
|
|
2217
3370
|
};
|
|
3371
|
+
/** Register an event listener that will be notified with the company's credit balances (keyed by credit ID) whenever they change */
|
|
3372
|
+
addCreditBalanceListener = (listener) => {
|
|
3373
|
+
this.creditBalanceListeners.add(listener);
|
|
3374
|
+
return () => {
|
|
3375
|
+
this.creditBalanceListeners.delete(listener);
|
|
3376
|
+
};
|
|
3377
|
+
};
|
|
2218
3378
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2219
3379
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2220
3380
|
if (listeners.size > 0) {
|
|
@@ -2278,6 +3438,17 @@ var Schematic = class {
|
|
|
2278
3438
|
});
|
|
2279
3439
|
});
|
|
2280
3440
|
};
|
|
3441
|
+
notifyCreditBalanceListeners = (value) => {
|
|
3442
|
+
const listeners = this.creditBalanceListeners ?? [];
|
|
3443
|
+
if (listeners.size > 0) {
|
|
3444
|
+
this.debug(`Notifying ${listeners.size} credit balance listeners`, {
|
|
3445
|
+
value
|
|
3446
|
+
});
|
|
3447
|
+
}
|
|
3448
|
+
listeners.forEach(
|
|
3449
|
+
(listener) => notifyCreditBalanceListener(listener, value)
|
|
3450
|
+
);
|
|
3451
|
+
};
|
|
2281
3452
|
};
|
|
2282
3453
|
var notifyPendingListener = (listener, value) => {
|
|
2283
3454
|
if (listener.length > 0) {
|
|
@@ -2307,25 +3478,862 @@ var notifyPlanListener = (listener, value) => {
|
|
|
2307
3478
|
listener();
|
|
2308
3479
|
}
|
|
2309
3480
|
};
|
|
3481
|
+
var notifyCreditBalanceListener = (listener, value) => {
|
|
3482
|
+
if (listener.length > 0) {
|
|
3483
|
+
listener(value);
|
|
3484
|
+
} else {
|
|
3485
|
+
listener();
|
|
3486
|
+
}
|
|
3487
|
+
};
|
|
2310
3488
|
|
|
2311
3489
|
// src/context/schematic.tsx
|
|
2312
|
-
var
|
|
3490
|
+
var import_react5 = __toESM(require("react"));
|
|
3491
|
+
|
|
3492
|
+
// src/billing/contract/index.ts
|
|
3493
|
+
function normalizeInvoiceQuery2(query) {
|
|
3494
|
+
return normalizeInvoiceQuery(query).includePending === true ? { includePending: true } : {};
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
// src/billing/store.ts
|
|
3498
|
+
var Resource = class {
|
|
3499
|
+
constructor(_fetcher, initial, _readiness = () => "ready") {
|
|
3500
|
+
this._fetcher = _fetcher;
|
|
3501
|
+
this._readiness = _readiness;
|
|
3502
|
+
this._loaded = initial !== void 0;
|
|
3503
|
+
this._snapshot = {
|
|
3504
|
+
data: initial,
|
|
3505
|
+
error: void 0,
|
|
3506
|
+
isPending: initial === void 0
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
_fetcher;
|
|
3510
|
+
_readiness;
|
|
3511
|
+
_snapshot;
|
|
3512
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
3513
|
+
_inflight;
|
|
3514
|
+
_extending;
|
|
3515
|
+
/** A refetch asked for mid-load; runs once that load lands. */
|
|
3516
|
+
_queued;
|
|
3517
|
+
_generation = 0;
|
|
3518
|
+
_loaded = false;
|
|
3519
|
+
get snapshot() {
|
|
3520
|
+
return this._snapshot;
|
|
3521
|
+
}
|
|
3522
|
+
get subscriberCount() {
|
|
3523
|
+
return this._listeners.size;
|
|
3524
|
+
}
|
|
3525
|
+
getSnapshot = () => this._snapshot;
|
|
3526
|
+
subscribe = (listener) => {
|
|
3527
|
+
this._listeners.add(listener);
|
|
3528
|
+
if (!this._loaded && this._inflight === void 0 && this._snapshot.error === void 0) {
|
|
3529
|
+
void this.load();
|
|
3530
|
+
}
|
|
3531
|
+
return () => {
|
|
3532
|
+
this._listeners.delete(listener);
|
|
3533
|
+
};
|
|
3534
|
+
};
|
|
3535
|
+
load() {
|
|
3536
|
+
if (this._inflight !== void 0) {
|
|
3537
|
+
return this._inflight;
|
|
3538
|
+
}
|
|
3539
|
+
const readiness = this._readiness();
|
|
3540
|
+
if (readiness !== "ready") {
|
|
3541
|
+
if (readiness === "never" && this._snapshot.isPending) {
|
|
3542
|
+
this._set({ ...this._snapshot, isPending: false });
|
|
3543
|
+
}
|
|
3544
|
+
return Promise.resolve();
|
|
3545
|
+
}
|
|
3546
|
+
const generation = ++this._generation;
|
|
3547
|
+
this._set({ ...this._snapshot, error: void 0, isPending: true });
|
|
3548
|
+
const run = Promise.resolve().then(() => this._fetcher()).then(
|
|
3549
|
+
(data) => {
|
|
3550
|
+
if (generation !== this._generation) return;
|
|
3551
|
+
this._loaded = true;
|
|
3552
|
+
this._set({ data, error: void 0, isPending: false });
|
|
3553
|
+
},
|
|
3554
|
+
(cause) => {
|
|
3555
|
+
if (generation !== this._generation) return;
|
|
3556
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
3557
|
+
this._set({ ...this._snapshot, error, isPending: false });
|
|
3558
|
+
}
|
|
3559
|
+
).finally(() => {
|
|
3560
|
+
if (generation === this._generation) {
|
|
3561
|
+
this._inflight = void 0;
|
|
3562
|
+
}
|
|
3563
|
+
});
|
|
3564
|
+
this._inflight = run;
|
|
3565
|
+
return run;
|
|
3566
|
+
}
|
|
3567
|
+
/**
|
|
3568
|
+
* Reloads; `data` holds its current value until the response lands. Asked
|
|
3569
|
+
* for mid-load, it runs again after: that request was built before
|
|
3570
|
+
* whatever prompted this one. Refetches queued on one load share the
|
|
3571
|
+
* re-run; a reset, seed, or clear in the meantime supersedes it.
|
|
3572
|
+
*/
|
|
3573
|
+
refetch() {
|
|
3574
|
+
if (this._inflight === void 0) {
|
|
3575
|
+
return this.load();
|
|
3576
|
+
}
|
|
3577
|
+
if (this._queued === void 0) {
|
|
3578
|
+
const generation = this._generation;
|
|
3579
|
+
const queued = this._inflight.then(() => {
|
|
3580
|
+
if (this._queued === queued) {
|
|
3581
|
+
this._queued = void 0;
|
|
3582
|
+
}
|
|
3583
|
+
if (generation !== this._generation) {
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3586
|
+
return this.load();
|
|
3587
|
+
});
|
|
3588
|
+
this._queued = queued;
|
|
3589
|
+
}
|
|
3590
|
+
return this._queued;
|
|
3591
|
+
}
|
|
3592
|
+
/**
|
|
3593
|
+
* Pages: `fetcher` receives the current data and returns what replaces it.
|
|
3594
|
+
* Never rejects — a caller that wants the failure reads `snapshot.error`,
|
|
3595
|
+
* and `data` keeps what was already fetched.
|
|
3596
|
+
*
|
|
3597
|
+
* A load already in flight wins: it is about to refresh the window this
|
|
3598
|
+
* would have appended to.
|
|
3599
|
+
*/
|
|
3600
|
+
extend(fetcher) {
|
|
3601
|
+
const current = this._snapshot.data;
|
|
3602
|
+
if (current === void 0) {
|
|
3603
|
+
return Promise.resolve();
|
|
3604
|
+
}
|
|
3605
|
+
if (this._readiness() !== "ready") {
|
|
3606
|
+
return Promise.resolve();
|
|
3607
|
+
}
|
|
3608
|
+
if (this._extending !== void 0) {
|
|
3609
|
+
return this._extending;
|
|
3610
|
+
}
|
|
3611
|
+
if (this._inflight !== void 0) {
|
|
3612
|
+
return this._inflight;
|
|
3613
|
+
}
|
|
3614
|
+
const generation = ++this._generation;
|
|
3615
|
+
this._set({ ...this._snapshot, error: void 0, isPending: true });
|
|
3616
|
+
const run = Promise.resolve().then(() => fetcher(current)).then(
|
|
3617
|
+
(data) => {
|
|
3618
|
+
if (generation !== this._generation) return;
|
|
3619
|
+
this._set({ data, error: void 0, isPending: false });
|
|
3620
|
+
},
|
|
3621
|
+
(cause) => {
|
|
3622
|
+
if (generation !== this._generation) return;
|
|
3623
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
3624
|
+
this._set({ ...this._snapshot, error, isPending: false });
|
|
3625
|
+
}
|
|
3626
|
+
).finally(() => {
|
|
3627
|
+
if (this._extending === run) {
|
|
3628
|
+
this._extending = void 0;
|
|
3629
|
+
}
|
|
3630
|
+
});
|
|
3631
|
+
this._extending = run;
|
|
3632
|
+
return run;
|
|
3633
|
+
}
|
|
3634
|
+
seed(data) {
|
|
3635
|
+
this._generation++;
|
|
3636
|
+
this._inflight = void 0;
|
|
3637
|
+
this._extending = void 0;
|
|
3638
|
+
this._queued = void 0;
|
|
3639
|
+
this._loaded = true;
|
|
3640
|
+
this._set({ data, error: void 0, isPending: false });
|
|
3641
|
+
}
|
|
3642
|
+
update(fn) {
|
|
3643
|
+
if (this._snapshot.data === void 0) return;
|
|
3644
|
+
this._generation++;
|
|
3645
|
+
this._inflight = void 0;
|
|
3646
|
+
this._extending = void 0;
|
|
3647
|
+
this._queued = void 0;
|
|
3648
|
+
this._set({ ...this._snapshot, data: fn(this._snapshot.data) });
|
|
3649
|
+
}
|
|
3650
|
+
/**
|
|
3651
|
+
* Forgets everything and stays empty — no data, no error, not pending.
|
|
3652
|
+
* What a resource holds when there is no session to hold it for: a session
|
|
3653
|
+
* ending is not a failure and must not surface as one.
|
|
3654
|
+
*/
|
|
3655
|
+
clear() {
|
|
3656
|
+
this._generation++;
|
|
3657
|
+
this._inflight = void 0;
|
|
3658
|
+
this._extending = void 0;
|
|
3659
|
+
this._queued = void 0;
|
|
3660
|
+
this._loaded = false;
|
|
3661
|
+
this._set({ data: void 0, error: void 0, isPending: false });
|
|
3662
|
+
}
|
|
3663
|
+
/** Forgets everything; reloads immediately if anyone is subscribed. */
|
|
3664
|
+
reset() {
|
|
3665
|
+
this._generation++;
|
|
3666
|
+
this._inflight = void 0;
|
|
3667
|
+
this._extending = void 0;
|
|
3668
|
+
this._queued = void 0;
|
|
3669
|
+
this._loaded = false;
|
|
3670
|
+
const readiness = this._readiness();
|
|
3671
|
+
const willLoad = this._listeners.size > 0 && readiness === "ready";
|
|
3672
|
+
this._set({
|
|
3673
|
+
data: void 0,
|
|
3674
|
+
error: void 0,
|
|
3675
|
+
isPending: willLoad || readiness === "waiting"
|
|
3676
|
+
});
|
|
3677
|
+
if (willLoad) {
|
|
3678
|
+
void this.load();
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
_set(next) {
|
|
3682
|
+
this._snapshot = next;
|
|
3683
|
+
for (const listener of this._listeners) {
|
|
3684
|
+
listener();
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
};
|
|
3688
|
+
function hashKey(params) {
|
|
3689
|
+
return JSON.stringify(canonical(params));
|
|
3690
|
+
}
|
|
3691
|
+
function canonical(value) {
|
|
3692
|
+
if (Array.isArray(value)) {
|
|
3693
|
+
return value.map(canonical);
|
|
3694
|
+
}
|
|
3695
|
+
if (value instanceof Date) {
|
|
3696
|
+
const time = value.getTime();
|
|
3697
|
+
return Number.isNaN(time) ? "Invalid Date" : value.toISOString();
|
|
3698
|
+
}
|
|
3699
|
+
if (value !== null && typeof value === "object") {
|
|
3700
|
+
const out = {};
|
|
3701
|
+
for (const key of Object.keys(value).sort()) {
|
|
3702
|
+
const v = value[key];
|
|
3703
|
+
if (v !== void 0) {
|
|
3704
|
+
out[key] = canonical(v);
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
return out;
|
|
3708
|
+
}
|
|
3709
|
+
return value ?? null;
|
|
3710
|
+
}
|
|
3711
|
+
var DEFAULT_EVICTION = { maxIdle: 4 };
|
|
3712
|
+
var KeyedResource = class {
|
|
3713
|
+
constructor(_fetcher, options = {}) {
|
|
3714
|
+
this._fetcher = _fetcher;
|
|
3715
|
+
this._readiness = options.readiness ?? (() => "ready");
|
|
3716
|
+
this._hash = options.hash ?? hashKey;
|
|
3717
|
+
this._eviction = {
|
|
3718
|
+
maxIdle: options.eviction?.maxIdle ?? DEFAULT_EVICTION.maxIdle
|
|
3719
|
+
};
|
|
3720
|
+
}
|
|
3721
|
+
_fetcher;
|
|
3722
|
+
_entries = /* @__PURE__ */ new Map();
|
|
3723
|
+
_hash;
|
|
3724
|
+
_eviction;
|
|
3725
|
+
_readiness;
|
|
3726
|
+
hash(params) {
|
|
3727
|
+
return this._hash(params);
|
|
3728
|
+
}
|
|
3729
|
+
get size() {
|
|
3730
|
+
return this._entries.size;
|
|
3731
|
+
}
|
|
3732
|
+
entries() {
|
|
3733
|
+
return Array.from(this._entries, ([key, e]) => ({ key, ...e }));
|
|
3734
|
+
}
|
|
3735
|
+
get(params) {
|
|
3736
|
+
const key = this._hash(params);
|
|
3737
|
+
const existing = this._entries.get(key);
|
|
3738
|
+
if (existing !== void 0) {
|
|
3739
|
+
this._entries.delete(key);
|
|
3740
|
+
this._entries.set(key, existing);
|
|
3741
|
+
return existing.resource;
|
|
3742
|
+
}
|
|
3743
|
+
const resource = new Resource(
|
|
3744
|
+
() => this._fetcher(params, resource.snapshot.data),
|
|
3745
|
+
void 0,
|
|
3746
|
+
this._readiness
|
|
3747
|
+
);
|
|
3748
|
+
this._entries.set(key, { params, resource });
|
|
3749
|
+
return resource;
|
|
3750
|
+
}
|
|
3751
|
+
has(params) {
|
|
3752
|
+
return this._entries.has(this._hash(params));
|
|
3753
|
+
}
|
|
3754
|
+
subscribe(params, listener) {
|
|
3755
|
+
const resource = this.get(params);
|
|
3756
|
+
const unsubscribe = resource.subscribe(listener);
|
|
3757
|
+
return () => {
|
|
3758
|
+
unsubscribe();
|
|
3759
|
+
this._evict();
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3762
|
+
seed(params, data) {
|
|
3763
|
+
this.get(params).seed(data);
|
|
3764
|
+
}
|
|
3765
|
+
evict(params) {
|
|
3766
|
+
return this._entries.delete(this._hash(params));
|
|
3767
|
+
}
|
|
3768
|
+
resetAll() {
|
|
3769
|
+
for (const [key, { resource }] of Array.from(this._entries)) {
|
|
3770
|
+
if (resource.subscriberCount === 0) {
|
|
3771
|
+
this._entries.delete(key);
|
|
3772
|
+
} else {
|
|
3773
|
+
resource.reset();
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
resumeAll() {
|
|
3778
|
+
for (const { resource } of this._entries.values()) {
|
|
3779
|
+
if (resource.subscriberCount === 0) {
|
|
3780
|
+
continue;
|
|
3781
|
+
}
|
|
3782
|
+
const { data, error } = resource.snapshot;
|
|
3783
|
+
if (data === void 0 || error !== void 0) {
|
|
3784
|
+
void resource.load();
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
clearAll() {
|
|
3789
|
+
for (const [key, { resource }] of Array.from(this._entries)) {
|
|
3790
|
+
if (resource.subscriberCount === 0) {
|
|
3791
|
+
this._entries.delete(key);
|
|
3792
|
+
} else {
|
|
3793
|
+
resource.clear();
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
invalidateAll() {
|
|
3798
|
+
for (const { resource } of this._entries.values()) {
|
|
3799
|
+
if (resource.snapshot.data !== void 0) {
|
|
3800
|
+
void resource.refetch();
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
_evict() {
|
|
3805
|
+
const idle = Array.from(this._entries).filter(
|
|
3806
|
+
([, e]) => e.resource.subscriberCount === 0
|
|
3807
|
+
);
|
|
3808
|
+
let excess = idle.length - this._eviction.maxIdle;
|
|
3809
|
+
for (const [key] of idle) {
|
|
3810
|
+
if (excess <= 0) break;
|
|
3811
|
+
this._entries.delete(key);
|
|
3812
|
+
excess -= 1;
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
};
|
|
3816
|
+
|
|
3817
|
+
// src/billing/client.ts
|
|
3818
|
+
function claimOf(client) {
|
|
3819
|
+
return { status: client.sessionStatus, key: client.sessionKey };
|
|
3820
|
+
}
|
|
3821
|
+
function claimFrom(session) {
|
|
3822
|
+
if (session === void 0) {
|
|
3823
|
+
return void 0;
|
|
3824
|
+
}
|
|
3825
|
+
return session === null ? { status: "ended", key: void 0 } : { status: "active", key: sessionKey(session) };
|
|
3826
|
+
}
|
|
3827
|
+
function judgeSeed(seedKey, claim) {
|
|
3828
|
+
if (claim.status === "ended") {
|
|
3829
|
+
return "drop";
|
|
3830
|
+
}
|
|
3831
|
+
if (seedKey === void 0) {
|
|
3832
|
+
return "adopt";
|
|
3833
|
+
}
|
|
3834
|
+
if (claim.status === "pending") {
|
|
3835
|
+
return "hold";
|
|
3836
|
+
}
|
|
3837
|
+
return seedKey === claim.key ? "adopt" : "drop";
|
|
3838
|
+
}
|
|
3839
|
+
var READINESS = {
|
|
3840
|
+
pending: "waiting",
|
|
3841
|
+
active: "ready",
|
|
3842
|
+
ended: "never"
|
|
3843
|
+
};
|
|
3844
|
+
var BillingStore = class {
|
|
3845
|
+
constructor(_client, initialData = {}, options = {}) {
|
|
3846
|
+
this._client = _client;
|
|
3847
|
+
this._pageSize = options.pageSize ?? INVOICE_PAGE_SIZE;
|
|
3848
|
+
this.invoices = new KeyedResource(
|
|
3849
|
+
(query, current) => this._reloadWindow(
|
|
3850
|
+
query,
|
|
3851
|
+
Math.max(this._pageSize, current?.invoices.length ?? 0)
|
|
3852
|
+
),
|
|
3853
|
+
// Waiting until connected; then a session still pending stays
|
|
3854
|
+
// pending, and one that has ended settles empty rather than recording
|
|
3855
|
+
// the client's refusal as an error.
|
|
3856
|
+
{
|
|
3857
|
+
readiness: () => this._connected ? READINESS[this._client.sessionStatus] : "waiting"
|
|
3858
|
+
}
|
|
3859
|
+
);
|
|
3860
|
+
if (initialData.invoices !== void 0) {
|
|
3861
|
+
this._held = {
|
|
3862
|
+
// Normalized the way the hook normalizes, or the caller asking for
|
|
3863
|
+
// it fetches the same page again.
|
|
3864
|
+
params: normalizeInvoiceQuery2(
|
|
3865
|
+
initialData.params?.invoices ?? DEFAULT_INVOICE_QUERY
|
|
3866
|
+
),
|
|
3867
|
+
data: initialData.invoices,
|
|
3868
|
+
key: initialData.sessionKey
|
|
3869
|
+
};
|
|
3870
|
+
this._settleSeed(claimFrom(options.session) ?? claimOf(this._client));
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
_client;
|
|
3874
|
+
invoices;
|
|
3875
|
+
_pageSize;
|
|
3876
|
+
_unsubscribe;
|
|
3877
|
+
_connected = false;
|
|
3878
|
+
_seeded = false;
|
|
3879
|
+
/** The session that prefetch was for, where it said. */
|
|
3880
|
+
_seedKey;
|
|
3881
|
+
/** A stamped prefetch waiting for a session to check it against. */
|
|
3882
|
+
_held;
|
|
3883
|
+
/**
|
|
3884
|
+
* Not done in the constructor: the provider arms it from an effect, and
|
|
3885
|
+
* React runs an effect, its cleanup, then the effect again under
|
|
3886
|
+
* StrictMode. A subscription made once at construction is torn down by
|
|
3887
|
+
* that cleanup and never comes back, leaving the store deaf to every
|
|
3888
|
+
* session change for the rest of the page.
|
|
3889
|
+
*
|
|
3890
|
+
* Also what opens the store: subscribers who arrived first have been
|
|
3891
|
+
* waiting, and this is the moment the session is known to be installed.
|
|
3892
|
+
*/
|
|
3893
|
+
connect() {
|
|
3894
|
+
this._unsubscribe?.();
|
|
3895
|
+
const unsubscribe = this._client.onSessionChange?.((event) => {
|
|
3896
|
+
if (event.type === "ended") {
|
|
3897
|
+
this._held = void 0;
|
|
3898
|
+
this._seeded = false;
|
|
3899
|
+
this.clearAll();
|
|
3900
|
+
} else if (event.type === "changed") {
|
|
3901
|
+
this._held = void 0;
|
|
3902
|
+
this._seeded = false;
|
|
3903
|
+
this.resetAll();
|
|
3904
|
+
} else {
|
|
3905
|
+
this._onStarted();
|
|
3906
|
+
}
|
|
3907
|
+
});
|
|
3908
|
+
this._unsubscribe = unsubscribe;
|
|
3909
|
+
if (!this._connected) {
|
|
3910
|
+
this._connected = true;
|
|
3911
|
+
this._settleSeed(claimOf(this._client));
|
|
3912
|
+
this.resumeAll();
|
|
3913
|
+
}
|
|
3914
|
+
return () => {
|
|
3915
|
+
unsubscribe?.();
|
|
3916
|
+
if (this._unsubscribe === unsubscribe) {
|
|
3917
|
+
this._unsubscribe = void 0;
|
|
3918
|
+
}
|
|
3919
|
+
};
|
|
3920
|
+
}
|
|
3921
|
+
_onStarted() {
|
|
3922
|
+
const claim = claimOf(this._client);
|
|
3923
|
+
this._settleSeed(claim);
|
|
3924
|
+
if (this._seeded && judgeSeed(this._seedKey, claim) !== "adopt") {
|
|
3925
|
+
this._seeded = false;
|
|
3926
|
+
this.resetAll();
|
|
3927
|
+
return;
|
|
3928
|
+
}
|
|
3929
|
+
this._seeded = false;
|
|
3930
|
+
this.resumeAll();
|
|
3931
|
+
}
|
|
3932
|
+
/** Adopts, keeps holding, or drops the prefetch, by what `claim` says. */
|
|
3933
|
+
_settleSeed(claim) {
|
|
3934
|
+
const held = this._held;
|
|
3935
|
+
if (held === void 0) {
|
|
3936
|
+
return;
|
|
3937
|
+
}
|
|
3938
|
+
const verdict = judgeSeed(held.key, claim);
|
|
3939
|
+
if (verdict === "hold") {
|
|
3940
|
+
return;
|
|
3941
|
+
}
|
|
3942
|
+
this._held = void 0;
|
|
3943
|
+
if (verdict === "adopt") {
|
|
3944
|
+
this.invoices.seed(held.params, held.data);
|
|
3945
|
+
this._seedKey = held.key;
|
|
3946
|
+
this._seeded = true;
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
resource(name) {
|
|
3950
|
+
return this[name];
|
|
3951
|
+
}
|
|
3952
|
+
/** Forgets every resource; subscribed ones reload, idle ones are dropped. */
|
|
3953
|
+
resetAll() {
|
|
3954
|
+
for (const name of RESOURCE_NAMES) {
|
|
3955
|
+
this[name].resetAll();
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
/** Forgets every resource and leaves them empty; nothing reloads. */
|
|
3959
|
+
clearAll() {
|
|
3960
|
+
for (const name of RESOURCE_NAMES) {
|
|
3961
|
+
this[name].clearAll();
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
/** Loads every resource that is subscribed and has nothing yet. */
|
|
3965
|
+
resumeAll() {
|
|
3966
|
+
for (const name of RESOURCE_NAMES) {
|
|
3967
|
+
this[name].resumeAll();
|
|
3968
|
+
}
|
|
3969
|
+
}
|
|
3970
|
+
/** Reloads every resource that has been loaded, keeping its current data. */
|
|
3971
|
+
invalidateAll() {
|
|
3972
|
+
for (const name of RESOURCE_NAMES) {
|
|
3973
|
+
this[name].invalidateAll();
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
/**
|
|
3977
|
+
* Appends the next page to the invoices list for `query`, when there is
|
|
3978
|
+
* one. A failure records the error on the resource and keeps the rows
|
|
3979
|
+
* already fetched; the returned promise never rejects.
|
|
3980
|
+
*/
|
|
3981
|
+
loadMoreInvoices(query = DEFAULT_INVOICE_QUERY) {
|
|
3982
|
+
const resource = this.invoices.get(normalizeInvoiceQuery2(query));
|
|
3983
|
+
if (resource.snapshot.data?.hasMore !== true) {
|
|
3984
|
+
return Promise.resolve();
|
|
3985
|
+
}
|
|
3986
|
+
return resource.extend(async (current) => {
|
|
3987
|
+
const page = await this._fetchInvoices(
|
|
3988
|
+
normalizeInvoiceQuery2(query),
|
|
3989
|
+
current.invoices.length,
|
|
3990
|
+
this._pageSize
|
|
3991
|
+
);
|
|
3992
|
+
const invoices = [...current.invoices, ...page.invoices];
|
|
3993
|
+
return {
|
|
3994
|
+
invoices,
|
|
3995
|
+
count: page.count,
|
|
3996
|
+
// From the count the page came back with, not the one the list was
|
|
3997
|
+
// built on: an invoice finalized between the two requests changes
|
|
3998
|
+
// what is left to load. An empty page ends the list whatever the
|
|
3999
|
+
// count says — the rows and the count are two queries, and a count
|
|
4000
|
+
// that outruns the rows would otherwise leave `hasMore` true for
|
|
4001
|
+
// good, with every further page fetching nothing.
|
|
4002
|
+
hasMore: page.invoices.length > 0 && invoices.length < page.count
|
|
4003
|
+
};
|
|
4004
|
+
});
|
|
4005
|
+
}
|
|
4006
|
+
dispose() {
|
|
4007
|
+
this._unsubscribe?.();
|
|
4008
|
+
}
|
|
4009
|
+
/**
|
|
4010
|
+
* Re-reads the window already loaded, in as many requests as the API's
|
|
4011
|
+
* page cap needs. A window paged past that cap still comes back whole:
|
|
4012
|
+
* asking for it in one request would be a 400, and asking for only the
|
|
4013
|
+
* first page would drop the rest.
|
|
4014
|
+
*/
|
|
4015
|
+
async _reloadWindow(query, window2) {
|
|
4016
|
+
const invoices = [];
|
|
4017
|
+
let count = 0;
|
|
4018
|
+
while (invoices.length < window2) {
|
|
4019
|
+
const page = await this._fetchInvoices(
|
|
4020
|
+
query,
|
|
4021
|
+
invoices.length,
|
|
4022
|
+
Math.min(INVOICE_MAX_PAGE_SIZE, window2 - invoices.length)
|
|
4023
|
+
);
|
|
4024
|
+
count = page.count;
|
|
4025
|
+
invoices.push(...page.invoices);
|
|
4026
|
+
if (page.invoices.length === 0 || invoices.length >= count) {
|
|
4027
|
+
break;
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
return {
|
|
4031
|
+
invoices,
|
|
4032
|
+
count,
|
|
4033
|
+
hasMore: invoices.length > 0 && invoices.length < count
|
|
4034
|
+
};
|
|
4035
|
+
}
|
|
4036
|
+
/**
|
|
4037
|
+
* Returns what the server said and nothing more: whether there is more to
|
|
4038
|
+
* load depends on the whole window, which only the caller assembling it
|
|
4039
|
+
* knows — `_reloadWindow` across its requests, and `loadMoreInvoices`
|
|
4040
|
+
* across the rows already loaded.
|
|
4041
|
+
*/
|
|
4042
|
+
_fetchInvoices(query, offset, limit) {
|
|
4043
|
+
return this._client.fetchInvoices({ ...query, limit, offset });
|
|
4044
|
+
}
|
|
4045
|
+
};
|
|
4046
|
+
var RESOURCE_NAMES = ["invoices"];
|
|
4047
|
+
|
|
4048
|
+
// src/billing/context.tsx
|
|
4049
|
+
var import_react2 = require("react");
|
|
4050
|
+
|
|
4051
|
+
// src/i18n/context.tsx
|
|
4052
|
+
var import_react = require("react");
|
|
4053
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
4054
|
+
var EMPTY = Object.freeze({});
|
|
4055
|
+
var SchematicI18nContext = (0, import_react.createContext)(EMPTY);
|
|
4056
|
+
function SchematicI18nProvider({
|
|
4057
|
+
children,
|
|
4058
|
+
locale,
|
|
4059
|
+
onMissingString,
|
|
4060
|
+
strings,
|
|
4061
|
+
translate
|
|
4062
|
+
}) {
|
|
4063
|
+
const parent = (0, import_react.useContext)(SchematicI18nContext);
|
|
4064
|
+
const value = (0, import_react.useMemo)(
|
|
4065
|
+
() => ({
|
|
4066
|
+
locale: locale ?? parent.locale,
|
|
4067
|
+
translate: translate ?? parent.translate,
|
|
4068
|
+
strings: strings === void 0 ? parent.strings : { ...parent.strings, ...strings },
|
|
4069
|
+
onMissingString: onMissingString ?? parent.onMissingString
|
|
4070
|
+
}),
|
|
4071
|
+
[locale, onMissingString, parent, strings, translate]
|
|
4072
|
+
);
|
|
4073
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchematicI18nContext.Provider, { value, children });
|
|
4074
|
+
}
|
|
4075
|
+
function useSchematicI18n() {
|
|
4076
|
+
return (0, import_react.useContext)(SchematicI18nContext);
|
|
4077
|
+
}
|
|
4078
|
+
function useSchematicLocale() {
|
|
4079
|
+
return (0, import_react.useContext)(SchematicI18nContext).locale;
|
|
4080
|
+
}
|
|
4081
|
+
function useSchematicTranslate() {
|
|
4082
|
+
return (0, import_react.useContext)(SchematicI18nContext).translate;
|
|
4083
|
+
}
|
|
4084
|
+
function useSchematicStrings() {
|
|
4085
|
+
return (0, import_react.useContext)(SchematicI18nContext).strings;
|
|
4086
|
+
}
|
|
4087
|
+
|
|
4088
|
+
// src/billing/context.tsx
|
|
4089
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
4090
|
+
var BillingDataContext = (0, import_react2.createContext)(
|
|
4091
|
+
void 0
|
|
4092
|
+
);
|
|
4093
|
+
var MISSING_BILLING_SOURCE_MESSAGE = "Schematic billing hooks need a SchematicProvider with a session, billingClient, or initialData, or a BillingDataProvider.";
|
|
4094
|
+
var missingSourceError = new Error(MISSING_BILLING_SOURCE_MESSAGE);
|
|
4095
|
+
var missingHandle = {
|
|
4096
|
+
data: void 0,
|
|
4097
|
+
error: missingSourceError,
|
|
4098
|
+
isPending: false,
|
|
4099
|
+
refetch: () => {
|
|
4100
|
+
}
|
|
4101
|
+
};
|
|
4102
|
+
var missingBillingSource = {
|
|
4103
|
+
subscribe: () => () => {
|
|
4104
|
+
},
|
|
4105
|
+
handle: () => missingHandle,
|
|
4106
|
+
loadMoreInvoices: () => Promise.resolve(),
|
|
4107
|
+
invalidateAll: () => {
|
|
4108
|
+
}
|
|
4109
|
+
};
|
|
4110
|
+
function useBillingDataSource() {
|
|
4111
|
+
return (0, import_react2.useContext)(BillingDataContext) ?? missingBillingSource;
|
|
4112
|
+
}
|
|
4113
|
+
function BillingDataProvider({
|
|
4114
|
+
children,
|
|
4115
|
+
data,
|
|
4116
|
+
locale,
|
|
4117
|
+
onLoadMoreInvoices,
|
|
4118
|
+
onMissingString,
|
|
4119
|
+
onRefetch,
|
|
4120
|
+
status,
|
|
4121
|
+
strings,
|
|
4122
|
+
translate
|
|
4123
|
+
}) {
|
|
4124
|
+
const source = (0, import_react2.useMemo)(() => {
|
|
4125
|
+
const handles = /* @__PURE__ */ new Map();
|
|
4126
|
+
return {
|
|
4127
|
+
subscribe: () => () => {
|
|
4128
|
+
},
|
|
4129
|
+
handle: (name) => {
|
|
4130
|
+
const cached = handles.get(name);
|
|
4131
|
+
if (cached !== void 0) {
|
|
4132
|
+
return cached;
|
|
4133
|
+
}
|
|
4134
|
+
const value = data[name];
|
|
4135
|
+
const override = status?.[name];
|
|
4136
|
+
const handle = {
|
|
4137
|
+
data: value,
|
|
4138
|
+
error: override?.error,
|
|
4139
|
+
isPending: override?.isPending ?? value === void 0,
|
|
4140
|
+
refetch: () => onRefetch?.(name)
|
|
4141
|
+
};
|
|
4142
|
+
handles.set(name, handle);
|
|
4143
|
+
return handle;
|
|
4144
|
+
},
|
|
4145
|
+
loadMoreInvoices: (query) => {
|
|
4146
|
+
onLoadMoreInvoices?.(query);
|
|
4147
|
+
return Promise.resolve();
|
|
4148
|
+
},
|
|
4149
|
+
invalidateAll: () => {
|
|
4150
|
+
}
|
|
4151
|
+
};
|
|
4152
|
+
}, [data, onLoadMoreInvoices, onRefetch, status]);
|
|
4153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BillingDataContext.Provider, { value: source, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4154
|
+
SchematicI18nProvider,
|
|
4155
|
+
{
|
|
4156
|
+
locale,
|
|
4157
|
+
strings,
|
|
4158
|
+
translate,
|
|
4159
|
+
onMissingString,
|
|
4160
|
+
children
|
|
4161
|
+
}
|
|
4162
|
+
) });
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
// src/billing/hooks.ts
|
|
4166
|
+
var import_react3 = require("react");
|
|
4167
|
+
function useStableParams(params) {
|
|
4168
|
+
const key = hashKey(params);
|
|
4169
|
+
const ref = (0, import_react3.useRef)({ key, params });
|
|
4170
|
+
if (ref.current.key !== key) {
|
|
4171
|
+
ref.current = { key, params };
|
|
4172
|
+
}
|
|
4173
|
+
return ref.current.params;
|
|
4174
|
+
}
|
|
4175
|
+
function useBillingResource(name, params) {
|
|
4176
|
+
const source = useBillingDataSource();
|
|
4177
|
+
const subscribe = (0, import_react3.useCallback)(
|
|
4178
|
+
(listener) => source.subscribe(name, params, listener),
|
|
4179
|
+
[name, params, source]
|
|
4180
|
+
);
|
|
4181
|
+
const getSnapshot = (0, import_react3.useCallback)(
|
|
4182
|
+
() => source.handle(name, params),
|
|
4183
|
+
[name, params, source]
|
|
4184
|
+
);
|
|
4185
|
+
return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
4186
|
+
}
|
|
4187
|
+
function useInvoices(query = DEFAULT_INVOICE_QUERY) {
|
|
4188
|
+
const source = useBillingDataSource();
|
|
4189
|
+
const params = useStableParams(normalizeInvoiceQuery2(query));
|
|
4190
|
+
const handle = useBillingResource("invoices", params);
|
|
4191
|
+
const loadMore = (0, import_react3.useCallback)(
|
|
4192
|
+
() => source.loadMoreInvoices(params),
|
|
4193
|
+
[params, source]
|
|
4194
|
+
);
|
|
4195
|
+
return (0, import_react3.useMemo)(() => ({ ...handle, loadMore }), [handle, loadMore]);
|
|
4196
|
+
}
|
|
4197
|
+
function useInvalidateBillingData() {
|
|
4198
|
+
return useBillingDataSource().invalidateAll;
|
|
4199
|
+
}
|
|
4200
|
+
|
|
4201
|
+
// src/billing/provider.tsx
|
|
4202
|
+
var import_react4 = require("react");
|
|
4203
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
4204
|
+
var SESSION_REPLACED_MESSAGE = "BillingProvider is moving its billingClient from one session to another. A client holds one session: if another provider shares this client, each will keep installing its own and show the other's data. Give each provider its own client.";
|
|
4205
|
+
function BillingProvider({
|
|
4206
|
+
billingClient,
|
|
4207
|
+
children,
|
|
4208
|
+
initialData,
|
|
4209
|
+
locale,
|
|
4210
|
+
onMissingString,
|
|
4211
|
+
session,
|
|
4212
|
+
strings,
|
|
4213
|
+
translate
|
|
4214
|
+
}) {
|
|
4215
|
+
const initialRef = (0, import_react4.useRef)(initialData);
|
|
4216
|
+
const install = () => {
|
|
4217
|
+
billingClient?.setSession?.(session);
|
|
4218
|
+
};
|
|
4219
|
+
(0, import_react4.useEffect)(() => {
|
|
4220
|
+
const claim = billingClient?.sessionKey;
|
|
4221
|
+
if (claim !== void 0 && session !== null && session !== void 0 && claim !== sessionKey(session)) {
|
|
4222
|
+
console.warn(SESSION_REPLACED_MESSAGE);
|
|
4223
|
+
}
|
|
4224
|
+
}, []);
|
|
4225
|
+
(0, import_react4.useEffect)(install);
|
|
4226
|
+
const seedSpent = (0, import_react4.useRef)(false);
|
|
4227
|
+
const store = (0, import_react4.useMemo)(
|
|
4228
|
+
() => billingClient === void 0 ? void 0 : new BillingStore(
|
|
4229
|
+
billingClient,
|
|
4230
|
+
seedSpent.current ? void 0 : initialRef.current,
|
|
4231
|
+
{
|
|
4232
|
+
// What `install` is about to say, so a stamped prefetch is
|
|
4233
|
+
// judged now rather than after the effect.
|
|
4234
|
+
session
|
|
4235
|
+
}
|
|
4236
|
+
),
|
|
4237
|
+
// `session` is read only when the store is built: the client learns
|
|
4238
|
+
// later sessions through `install`, and the store through the client.
|
|
4239
|
+
[billingClient]
|
|
4240
|
+
);
|
|
4241
|
+
(0, import_react4.useEffect)(() => {
|
|
4242
|
+
if (store !== void 0) {
|
|
4243
|
+
seedSpent.current = true;
|
|
4244
|
+
}
|
|
4245
|
+
}, [store]);
|
|
4246
|
+
(0, import_react4.useEffect)(() => store?.connect(), [store]);
|
|
4247
|
+
const source = (0, import_react4.useMemo)(() => {
|
|
4248
|
+
if (store === void 0) {
|
|
4249
|
+
return initialRef.current === void 0 ? void 0 : staticSource(initialRef.current);
|
|
4250
|
+
}
|
|
4251
|
+
const handles = /* @__PURE__ */ new WeakMap();
|
|
4252
|
+
const handle = (name, params) => {
|
|
4253
|
+
const resource = store.resource(name).get(params);
|
|
4254
|
+
const snapshot = resource.getSnapshot();
|
|
4255
|
+
const cached = handles.get(resource);
|
|
4256
|
+
if (cached !== void 0 && cached.snapshot === snapshot) {
|
|
4257
|
+
return cached.handle;
|
|
4258
|
+
}
|
|
4259
|
+
const next = {
|
|
4260
|
+
...snapshot,
|
|
4261
|
+
refetch: () => void resource.refetch()
|
|
4262
|
+
};
|
|
4263
|
+
handles.set(resource, { snapshot, handle: next });
|
|
4264
|
+
return next;
|
|
4265
|
+
};
|
|
4266
|
+
return {
|
|
4267
|
+
subscribe: (name, params, listener) => store.resource(name).subscribe(params, listener),
|
|
4268
|
+
handle,
|
|
4269
|
+
loadMoreInvoices: (query) => store.loadMoreInvoices(query),
|
|
4270
|
+
invalidateAll: () => store.invalidateAll()
|
|
4271
|
+
};
|
|
4272
|
+
}, [store]);
|
|
4273
|
+
const localized = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4274
|
+
SchematicI18nProvider,
|
|
4275
|
+
{
|
|
4276
|
+
locale,
|
|
4277
|
+
strings,
|
|
4278
|
+
translate,
|
|
4279
|
+
onMissingString,
|
|
4280
|
+
children
|
|
4281
|
+
}
|
|
4282
|
+
);
|
|
4283
|
+
if (source === void 0) {
|
|
4284
|
+
return localized;
|
|
4285
|
+
}
|
|
4286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BillingDataContext.Provider, { value: source, children: localized });
|
|
4287
|
+
}
|
|
4288
|
+
function staticSource(data) {
|
|
4289
|
+
const handles = /* @__PURE__ */ new Map();
|
|
4290
|
+
return {
|
|
4291
|
+
subscribe: () => () => {
|
|
4292
|
+
},
|
|
4293
|
+
handle: (name) => {
|
|
4294
|
+
const cached = handles.get(name);
|
|
4295
|
+
if (cached !== void 0) {
|
|
4296
|
+
return cached;
|
|
4297
|
+
}
|
|
4298
|
+
const value = data[name];
|
|
4299
|
+
const next = {
|
|
4300
|
+
data: value,
|
|
4301
|
+
error: void 0,
|
|
4302
|
+
isPending: value === void 0,
|
|
4303
|
+
refetch: () => {
|
|
4304
|
+
}
|
|
4305
|
+
};
|
|
4306
|
+
handles.set(name, next);
|
|
4307
|
+
return next;
|
|
4308
|
+
},
|
|
4309
|
+
loadMoreInvoices: () => Promise.resolve(),
|
|
4310
|
+
invalidateAll: () => {
|
|
4311
|
+
}
|
|
4312
|
+
};
|
|
4313
|
+
}
|
|
2313
4314
|
|
|
2314
4315
|
// src/version.ts
|
|
2315
|
-
var version2 = "1.
|
|
4316
|
+
var version2 = "1.6.0";
|
|
2316
4317
|
|
|
2317
4318
|
// src/context/schematic.tsx
|
|
2318
|
-
var
|
|
2319
|
-
var SchematicContext = (0,
|
|
4319
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
4320
|
+
var SchematicContext = (0, import_react5.createContext)(
|
|
2320
4321
|
null
|
|
2321
4322
|
);
|
|
2322
4323
|
var SchematicProvider = ({
|
|
4324
|
+
session,
|
|
4325
|
+
billingClient,
|
|
2323
4326
|
children,
|
|
2324
4327
|
client: providedClient,
|
|
4328
|
+
initialData,
|
|
4329
|
+
locale,
|
|
4330
|
+
onMissingString,
|
|
2325
4331
|
publishableKey,
|
|
4332
|
+
strings,
|
|
4333
|
+
translate,
|
|
2326
4334
|
...clientOpts
|
|
2327
4335
|
}) => {
|
|
2328
|
-
const initialOptsRef = (0,
|
|
4336
|
+
const initialOptsRef = (0, import_react5.useRef)({
|
|
2329
4337
|
publishableKey,
|
|
2330
4338
|
useWebSocket: true,
|
|
2331
4339
|
additionalHeaders: {
|
|
@@ -2333,7 +4341,7 @@ var SchematicProvider = ({
|
|
|
2333
4341
|
},
|
|
2334
4342
|
...clientOpts
|
|
2335
4343
|
});
|
|
2336
|
-
const client = (0,
|
|
4344
|
+
const client = (0, import_react5.useMemo)(() => {
|
|
2337
4345
|
if (providedClient) {
|
|
2338
4346
|
return providedClient;
|
|
2339
4347
|
}
|
|
@@ -2341,7 +4349,7 @@ var SchematicProvider = ({
|
|
|
2341
4349
|
...initialOptsRef.current
|
|
2342
4350
|
});
|
|
2343
4351
|
}, [providedClient]);
|
|
2344
|
-
(0,
|
|
4352
|
+
(0, import_react5.useEffect)(() => {
|
|
2345
4353
|
return () => {
|
|
2346
4354
|
if (!providedClient) {
|
|
2347
4355
|
client.cleanup().catch((error) => {
|
|
@@ -2350,16 +4358,46 @@ var SchematicProvider = ({
|
|
|
2350
4358
|
}
|
|
2351
4359
|
};
|
|
2352
4360
|
}, [client, providedClient]);
|
|
2353
|
-
const contextValue = (0,
|
|
4361
|
+
const contextValue = (0, import_react5.useMemo)(
|
|
2354
4362
|
() => ({
|
|
2355
4363
|
client
|
|
2356
4364
|
}),
|
|
2357
4365
|
[client]
|
|
2358
4366
|
);
|
|
2359
|
-
|
|
4367
|
+
const { apiUrl, additionalHeaders } = initialOptsRef.current;
|
|
4368
|
+
const providedApiUrl = providedClient?.apiUrl;
|
|
4369
|
+
const resolvedBillingClient = (0, import_react5.useMemo)(
|
|
4370
|
+
() => billingClient ?? new SchematicBillingClient({
|
|
4371
|
+
session,
|
|
4372
|
+
apiUrl: apiUrl ?? providedApiUrl,
|
|
4373
|
+
// Read as they stand when a client is built: headers do not change
|
|
4374
|
+
// where the token goes, so they are no reason to build one.
|
|
4375
|
+
additionalHeaders: {
|
|
4376
|
+
...providedClient?.additionalHeaders,
|
|
4377
|
+
...additionalHeaders
|
|
4378
|
+
}
|
|
4379
|
+
}),
|
|
4380
|
+
// `session` is deliberately absent: `BillingProvider` forwards it through
|
|
4381
|
+
// `setSession`, so a token change resets the billing resources without
|
|
4382
|
+
// rebuilding the client.
|
|
4383
|
+
[additionalHeaders, apiUrl, billingClient, providedApiUrl]
|
|
4384
|
+
);
|
|
4385
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SchematicContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4386
|
+
BillingProvider,
|
|
4387
|
+
{
|
|
4388
|
+
billingClient: resolvedBillingClient,
|
|
4389
|
+
initialData,
|
|
4390
|
+
locale,
|
|
4391
|
+
session,
|
|
4392
|
+
strings,
|
|
4393
|
+
translate,
|
|
4394
|
+
onMissingString,
|
|
4395
|
+
children
|
|
4396
|
+
}
|
|
4397
|
+
) });
|
|
2360
4398
|
};
|
|
2361
4399
|
var useSchematic = () => {
|
|
2362
|
-
const context =
|
|
4400
|
+
const context = import_react5.default.useContext(SchematicContext);
|
|
2363
4401
|
if (context === null) {
|
|
2364
4402
|
throw new Error("useSchematic must be used within a SchematicProvider");
|
|
2365
4403
|
}
|
|
@@ -2367,11 +4405,11 @@ var useSchematic = () => {
|
|
|
2367
4405
|
};
|
|
2368
4406
|
|
|
2369
4407
|
// src/hooks/schematic.ts
|
|
2370
|
-
var
|
|
4408
|
+
var import_react6 = require("react");
|
|
2371
4409
|
var useSchematicClient = (opts) => {
|
|
2372
4410
|
const schematic = useSchematic();
|
|
2373
4411
|
const { client } = opts ?? {};
|
|
2374
|
-
return (0,
|
|
4412
|
+
return (0, import_react6.useMemo)(() => {
|
|
2375
4413
|
if (client) {
|
|
2376
4414
|
return client;
|
|
2377
4415
|
}
|
|
@@ -2380,7 +4418,7 @@ var useSchematicClient = (opts) => {
|
|
|
2380
4418
|
};
|
|
2381
4419
|
var useSchematicContext = (opts) => {
|
|
2382
4420
|
const client = useSchematicClient(opts);
|
|
2383
|
-
return (0,
|
|
4421
|
+
return (0, import_react6.useMemo)(
|
|
2384
4422
|
() => ({
|
|
2385
4423
|
setContext: client.setContext.bind(client)
|
|
2386
4424
|
}),
|
|
@@ -2389,33 +4427,33 @@ var useSchematicContext = (opts) => {
|
|
|
2389
4427
|
};
|
|
2390
4428
|
var useSchematicEvents = (opts) => {
|
|
2391
4429
|
const client = useSchematicClient(opts);
|
|
2392
|
-
const track = (0,
|
|
4430
|
+
const track = (0, import_react6.useCallback)(
|
|
2393
4431
|
(...args) => client.track(...args),
|
|
2394
4432
|
[client]
|
|
2395
4433
|
);
|
|
2396
|
-
const identify = (0,
|
|
4434
|
+
const identify = (0, import_react6.useCallback)(
|
|
2397
4435
|
(...args) => client.identify(...args),
|
|
2398
4436
|
[client]
|
|
2399
4437
|
);
|
|
2400
|
-
return (0,
|
|
4438
|
+
return (0, import_react6.useMemo)(() => ({ track, identify }), [track, identify]);
|
|
2401
4439
|
};
|
|
2402
4440
|
var useSchematicFlag = (key, opts) => {
|
|
2403
4441
|
const client = useSchematicClient(opts);
|
|
2404
4442
|
const fallback = opts?.fallback ?? false;
|
|
2405
|
-
const subscribe = (0,
|
|
4443
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
2406
4444
|
(callback) => client.addFlagValueListener(key, callback),
|
|
2407
4445
|
[client, key]
|
|
2408
4446
|
);
|
|
2409
|
-
const getSnapshot = (0,
|
|
4447
|
+
const getSnapshot = (0, import_react6.useCallback)(() => {
|
|
2410
4448
|
const value = client.getFlagValue(key);
|
|
2411
4449
|
return typeof value === "undefined" ? fallback : value;
|
|
2412
4450
|
}, [client, key, fallback]);
|
|
2413
|
-
return (0,
|
|
4451
|
+
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => fallback);
|
|
2414
4452
|
};
|
|
2415
4453
|
var useSchematicEntitlement = (key, opts) => {
|
|
2416
4454
|
const client = useSchematicClient(opts);
|
|
2417
4455
|
const fallback = opts?.fallback ?? false;
|
|
2418
|
-
const fallbackCheck = (0,
|
|
4456
|
+
const fallbackCheck = (0, import_react6.useMemo)(
|
|
2419
4457
|
() => ({
|
|
2420
4458
|
flag: key,
|
|
2421
4459
|
reason: "Fallback",
|
|
@@ -2423,20 +4461,20 @@ var useSchematicEntitlement = (key, opts) => {
|
|
|
2423
4461
|
}),
|
|
2424
4462
|
[key, fallback]
|
|
2425
4463
|
);
|
|
2426
|
-
const subscribe = (0,
|
|
4464
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
2427
4465
|
(callback) => client.addFlagCheckListener(key, callback),
|
|
2428
4466
|
[client, key]
|
|
2429
4467
|
);
|
|
2430
|
-
const getSnapshot = (0,
|
|
4468
|
+
const getSnapshot = (0, import_react6.useCallback)(() => {
|
|
2431
4469
|
const check = client.getFlagCheck(key);
|
|
2432
4470
|
return check ?? fallbackCheck;
|
|
2433
4471
|
}, [client, key, fallbackCheck]);
|
|
2434
|
-
return (0,
|
|
4472
|
+
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackCheck);
|
|
2435
4473
|
};
|
|
2436
4474
|
var useSchematicPlan = (opts) => {
|
|
2437
4475
|
const client = useSchematicClient(opts);
|
|
2438
4476
|
const fallback = opts?.fallback;
|
|
2439
|
-
const fallbackPlan = (0,
|
|
4477
|
+
const fallbackPlan = (0, import_react6.useMemo)(
|
|
2440
4478
|
() => fallback,
|
|
2441
4479
|
[
|
|
2442
4480
|
fallback?.id,
|
|
@@ -2445,24 +4483,52 @@ var useSchematicPlan = (opts) => {
|
|
|
2445
4483
|
fallback?.trialStatus
|
|
2446
4484
|
]
|
|
2447
4485
|
);
|
|
2448
|
-
const subscribe = (0,
|
|
4486
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
2449
4487
|
(callback) => client.addPlanListener(callback),
|
|
2450
4488
|
[client]
|
|
2451
4489
|
);
|
|
2452
|
-
const getSnapshot = (0,
|
|
4490
|
+
const getSnapshot = (0, import_react6.useCallback)(() => {
|
|
2453
4491
|
const plan = client.getPlan();
|
|
2454
4492
|
return plan ?? fallbackPlan;
|
|
2455
4493
|
}, [client, fallbackPlan]);
|
|
2456
|
-
return (0,
|
|
4494
|
+
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackPlan);
|
|
4495
|
+
};
|
|
4496
|
+
var useSchematicCreditBalance = (creditId, opts) => {
|
|
4497
|
+
const client = useSchematicClient(opts);
|
|
4498
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
4499
|
+
(callback) => client.addCreditBalanceListener(callback),
|
|
4500
|
+
[client]
|
|
4501
|
+
);
|
|
4502
|
+
const getSnapshot = (0, import_react6.useCallback)(
|
|
4503
|
+
() => creditId === void 0 ? void 0 : client.getCreditBalance(creditId),
|
|
4504
|
+
[client, creditId]
|
|
4505
|
+
);
|
|
4506
|
+
const balance = (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
|
|
4507
|
+
const isPendingSubscribe = (0, import_react6.useCallback)(
|
|
4508
|
+
(callback) => client.addIsPendingListener(callback),
|
|
4509
|
+
[client]
|
|
4510
|
+
);
|
|
4511
|
+
const isPending = (0, import_react6.useSyncExternalStore)(
|
|
4512
|
+
isPendingSubscribe,
|
|
4513
|
+
() => client.getIsPending(),
|
|
4514
|
+
() => true
|
|
4515
|
+
);
|
|
4516
|
+
return (0, import_react6.useMemo)(
|
|
4517
|
+
() => ({
|
|
4518
|
+
balance: balance?.settled ?? 0,
|
|
4519
|
+
isLoading: balance === void 0 && isPending
|
|
4520
|
+
}),
|
|
4521
|
+
[balance, isPending]
|
|
4522
|
+
);
|
|
2457
4523
|
};
|
|
2458
4524
|
var useSchematicIsPending = (opts) => {
|
|
2459
4525
|
const client = useSchematicClient(opts);
|
|
2460
|
-
const subscribe = (0,
|
|
4526
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
2461
4527
|
(callback) => client.addIsPendingListener(callback),
|
|
2462
4528
|
[client]
|
|
2463
4529
|
);
|
|
2464
|
-
const getSnapshot = (0,
|
|
2465
|
-
return (0,
|
|
4530
|
+
const getSnapshot = (0, import_react6.useCallback)(() => client.getIsPending(), [client]);
|
|
4531
|
+
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => true);
|
|
2466
4532
|
};
|
|
2467
4533
|
/*! Bundled license information:
|
|
2468
4534
|
|