@monetize.software/sdk 3.0.0-alpha.4 → 3.0.0-alpha.5
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/dist/chunks/PaywallUI-BD5hRY2P.js +26 -0
- package/dist/chunks/PaywallUI-BD5hRY2P.js.map +1 -0
- package/dist/chunks/PaywallUI-D7lp-bC5.js +3206 -0
- package/dist/chunks/PaywallUI-D7lp-bC5.js.map +1 -0
- package/dist/chunks/ar-BCHXVoE2.js +114 -0
- package/dist/chunks/ar-BCHXVoE2.js.map +1 -0
- package/dist/chunks/ar-CsJNZJSr.js +2 -0
- package/dist/chunks/ar-CsJNZJSr.js.map +1 -0
- package/dist/chunks/cs-B5NqpTW_.js +110 -0
- package/dist/chunks/cs-B5NqpTW_.js.map +1 -0
- package/dist/chunks/cs-BydWUC0e.js +2 -0
- package/dist/chunks/cs-BydWUC0e.js.map +1 -0
- package/dist/chunks/da-BJrGZ3LD.js +110 -0
- package/dist/chunks/da-BJrGZ3LD.js.map +1 -0
- package/dist/chunks/da-DNhiAQnh.js +2 -0
- package/dist/chunks/da-DNhiAQnh.js.map +1 -0
- package/dist/chunks/de-H8ztFOie.js +2 -0
- package/dist/chunks/de-H8ztFOie.js.map +1 -0
- package/dist/chunks/de-aepBKwsb.js +130 -0
- package/dist/chunks/de-aepBKwsb.js.map +1 -0
- package/dist/chunks/el-DRfoadtI.js +2 -0
- package/dist/chunks/el-DRfoadtI.js.map +1 -0
- package/dist/chunks/el-DTLQoX2D.js +114 -0
- package/dist/chunks/el-DTLQoX2D.js.map +1 -0
- package/dist/chunks/es-CLutF-D_.js +130 -0
- package/dist/chunks/es-CLutF-D_.js.map +1 -0
- package/dist/chunks/es-GlaYesNR.js +2 -0
- package/dist/chunks/es-GlaYesNR.js.map +1 -0
- package/dist/chunks/fi-BIHFyScH.js +2 -0
- package/dist/chunks/fi-BIHFyScH.js.map +1 -0
- package/dist/chunks/fi-DZ4csxqk.js +110 -0
- package/dist/chunks/fi-DZ4csxqk.js.map +1 -0
- package/dist/chunks/fr-BtZILUNZ.js +2 -0
- package/dist/chunks/fr-BtZILUNZ.js.map +1 -0
- package/dist/chunks/fr-jJU1SSpj.js +130 -0
- package/dist/chunks/fr-jJU1SSpj.js.map +1 -0
- package/dist/chunks/he-D9obGPNj.js +114 -0
- package/dist/chunks/he-D9obGPNj.js.map +1 -0
- package/dist/chunks/he-vSDRE4Nn.js +2 -0
- package/dist/chunks/he-vSDRE4Nn.js.map +1 -0
- package/dist/chunks/hi-B90FsnP6.js +2 -0
- package/dist/chunks/hi-B90FsnP6.js.map +1 -0
- package/dist/chunks/hi-pM8SQwZ3.js +114 -0
- package/dist/chunks/hi-pM8SQwZ3.js.map +1 -0
- package/dist/chunks/hu-DWVFODsS.js +2 -0
- package/dist/chunks/hu-DWVFODsS.js.map +1 -0
- package/dist/chunks/hu-E0m9WgbD.js +110 -0
- package/dist/chunks/hu-E0m9WgbD.js.map +1 -0
- package/dist/chunks/id-C6poPvby.js +110 -0
- package/dist/chunks/id-C6poPvby.js.map +1 -0
- package/dist/chunks/id-Ce2gzMVT.js +2 -0
- package/dist/chunks/id-Ce2gzMVT.js.map +1 -0
- package/dist/chunks/it-B2RSFyVd.js +130 -0
- package/dist/chunks/it-B2RSFyVd.js.map +1 -0
- package/dist/chunks/it-u-Gu44bl.js +2 -0
- package/dist/chunks/it-u-Gu44bl.js.map +1 -0
- package/dist/chunks/ja-CM-VgVG6.js +134 -0
- package/dist/chunks/ja-CM-VgVG6.js.map +1 -0
- package/dist/chunks/ja-CQy8RaRa.js +2 -0
- package/dist/chunks/ja-CQy8RaRa.js.map +1 -0
- package/dist/chunks/ko-BRnb7vJ7.js +2 -0
- package/dist/chunks/ko-BRnb7vJ7.js.map +1 -0
- package/dist/chunks/ko-C451fA21.js +134 -0
- package/dist/chunks/ko-C451fA21.js.map +1 -0
- package/dist/chunks/nl-CJelco6J.js +2 -0
- package/dist/chunks/nl-CJelco6J.js.map +1 -0
- package/dist/chunks/nl-DzQfJPo2.js +130 -0
- package/dist/chunks/nl-DzQfJPo2.js.map +1 -0
- package/dist/chunks/no-B51be8KT.js +110 -0
- package/dist/chunks/no-B51be8KT.js.map +1 -0
- package/dist/chunks/no-BwTjSZ4K.js +2 -0
- package/dist/chunks/no-BwTjSZ4K.js.map +1 -0
- package/dist/chunks/pl-5rTEkvfY.js +110 -0
- package/dist/chunks/pl-5rTEkvfY.js.map +1 -0
- package/dist/chunks/pl-kO82vcjb.js +2 -0
- package/dist/chunks/pl-kO82vcjb.js.map +1 -0
- package/dist/chunks/pt-CsJzaSjg.js +2 -0
- package/dist/chunks/pt-CsJzaSjg.js.map +1 -0
- package/dist/chunks/pt-JwqffZ9u.js +130 -0
- package/dist/chunks/pt-JwqffZ9u.js.map +1 -0
- package/dist/chunks/ro-BE_wJ1td.js +110 -0
- package/dist/chunks/ro-BE_wJ1td.js.map +1 -0
- package/dist/chunks/ro-ue15Ina4.js +2 -0
- package/dist/chunks/ro-ue15Ina4.js.map +1 -0
- package/dist/chunks/ru-B1iMOhX0.js +2 -0
- package/dist/chunks/ru-B1iMOhX0.js.map +1 -0
- package/dist/chunks/ru-BviATvLb.js +124 -0
- package/dist/chunks/ru-BviATvLb.js.map +1 -0
- package/dist/chunks/sv-CkNYpUVy.js +2 -0
- package/dist/chunks/sv-CkNYpUVy.js.map +1 -0
- package/dist/chunks/sv-DabGF9WL.js +110 -0
- package/dist/chunks/sv-DabGF9WL.js.map +1 -0
- package/dist/chunks/th-BiF-bNo0.js +114 -0
- package/dist/chunks/th-BiF-bNo0.js.map +1 -0
- package/dist/chunks/th-Cu80HK4y.js +2 -0
- package/dist/chunks/th-Cu80HK4y.js.map +1 -0
- package/dist/chunks/tr-B7c0afXV.js +2 -0
- package/dist/chunks/tr-B7c0afXV.js.map +1 -0
- package/dist/chunks/tr-xZuly8X8.js +110 -0
- package/dist/chunks/tr-xZuly8X8.js.map +1 -0
- package/dist/chunks/uk-BO106B0H.js +2 -0
- package/dist/chunks/uk-BO106B0H.js.map +1 -0
- package/dist/chunks/uk-KlkAaHuy.js +124 -0
- package/dist/chunks/uk-KlkAaHuy.js.map +1 -0
- package/dist/chunks/vi-BVCeumNE.js +110 -0
- package/dist/chunks/vi-BVCeumNE.js.map +1 -0
- package/dist/chunks/vi-CZ6ow40D.js +2 -0
- package/dist/chunks/vi-CZ6ow40D.js.map +1 -0
- package/dist/chunks/zh-BhP80WI1.js +2 -0
- package/dist/chunks/zh-BhP80WI1.js.map +1 -0
- package/dist/chunks/zh-C_ghwmqi.js +134 -0
- package/dist/chunks/zh-C_ghwmqi.js.map +1 -0
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +81 -5
- package/dist/core.js +209 -171
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +81 -5
- package/dist/index.js +1 -1
- package/dist/ui.cjs +1 -1
- package/dist/ui.d.ts +81 -5
- package/dist/ui.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/PaywallUI-2bwf2scV.js +0 -2277
- package/dist/chunks/PaywallUI-2bwf2scV.js.map +0 -1
- package/dist/chunks/PaywallUI-Bu51__PT.js +0 -26
- package/dist/chunks/PaywallUI-Bu51__PT.js.map +0 -1
package/dist/core.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
class
|
|
1
|
+
class n extends Error {
|
|
2
2
|
constructor(t, e, s = {}) {
|
|
3
3
|
super(e), this.name = "PaywallError", this.code = t, this.status = s.status, this.cause = s.cause;
|
|
4
4
|
}
|
|
5
5
|
}
|
|
6
|
-
class D extends
|
|
6
|
+
class D extends n {
|
|
7
7
|
constructor(t) {
|
|
8
8
|
super("not_enough_queries", t.message ?? "Not enough queries", {
|
|
9
9
|
status: 402
|
|
@@ -16,36 +16,36 @@ class E {
|
|
|
16
16
|
this.opts = t;
|
|
17
17
|
}
|
|
18
18
|
async request(t, e = {}) {
|
|
19
|
-
const s = new URL(t, this.opts.apiOrigin).toString(), a = this.opts.fetch ?? fetch,
|
|
20
|
-
|
|
19
|
+
const s = new URL(t, this.opts.apiOrigin).toString(), a = this.opts.fetch ?? fetch, r = new Headers(e.headers);
|
|
20
|
+
r.set("Accept", "application/json"), r.set("X-SDK-Version", m), r.set("X-Paywall-Id", this.opts.paywallId), this.opts.capabilities?.length && r.set("X-SDK-Capabilities", this.opts.capabilities.join(","));
|
|
21
21
|
const o = await this.opts.getAuthToken?.();
|
|
22
|
-
o &&
|
|
23
|
-
const
|
|
24
|
-
e.body && !
|
|
25
|
-
let
|
|
22
|
+
o && r.set("Authorization", `Bearer ${o}`);
|
|
23
|
+
const d = typeof FormData < "u" && e.body instanceof FormData;
|
|
24
|
+
e.body && !r.has("Content-Type") && !d && r.set("Content-Type", "application/json");
|
|
25
|
+
let u;
|
|
26
26
|
try {
|
|
27
|
-
|
|
27
|
+
u = await a(s, {
|
|
28
28
|
...e,
|
|
29
|
-
headers:
|
|
29
|
+
headers: r,
|
|
30
30
|
credentials: "omit"
|
|
31
31
|
});
|
|
32
32
|
} catch (c) {
|
|
33
|
-
throw (c && typeof c == "object" && "name" in c ? c.name : void 0) === "AbortError" ? new
|
|
33
|
+
throw (c && typeof c == "object" && "name" in c ? c.name : void 0) === "AbortError" ? new n("aborted", "Request aborted", { cause: c }) : new n("network_error", "Network request failed", { cause: c });
|
|
34
34
|
}
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
37
|
-
const c =
|
|
38
|
-
throw new
|
|
35
|
+
const y = (u.headers.get("content-type") ?? "").includes("application/json") ? await u.json().catch(() => null) : null;
|
|
36
|
+
if (!u.ok) {
|
|
37
|
+
const c = y && typeof y == "object" && "code" in y && String(y.code) || `http_${u.status}`, g = y && typeof y == "object" && "message" in y && String(y.message) || u.statusText || "Request failed";
|
|
38
|
+
throw new n(c, g, { status: u.status, cause: y });
|
|
39
39
|
}
|
|
40
|
-
return
|
|
40
|
+
return y;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
class q {
|
|
44
44
|
constructor(t) {
|
|
45
45
|
if (!t.paywallId)
|
|
46
|
-
throw new
|
|
46
|
+
throw new n("invalid_config", "paywallId is required");
|
|
47
47
|
if (!t.apiOrigin)
|
|
48
|
-
throw new
|
|
48
|
+
throw new n(
|
|
49
49
|
"invalid_config",
|
|
50
50
|
"apiOrigin is required. Pass the paywall custom_domain configured in the platform."
|
|
51
51
|
);
|
|
@@ -61,15 +61,15 @@ class q {
|
|
|
61
61
|
s.searchParams.set("paywall_id", this.paywallId);
|
|
62
62
|
const a = new Headers(t.headers);
|
|
63
63
|
a.set("X-SDK-Version", m), a.set("X-Paywall-Id", this.paywallId), this.capabilities?.length && a.set("X-SDK-Capabilities", this.capabilities.join(","));
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const o = typeof FormData < "u" && t.body instanceof FormData,
|
|
64
|
+
const r = await this.auth?.getAccessToken();
|
|
65
|
+
r ? a.set("Authorization", `Bearer ${r}`) : this.userId && a.set("X-User-ID", this.userId);
|
|
66
|
+
const o = typeof FormData < "u" && t.body instanceof FormData, d = typeof Blob < "u" && t.body instanceof Blob, u = typeof ReadableStream < "u" && t.body instanceof ReadableStream, f = typeof t.body == "string";
|
|
67
67
|
let h;
|
|
68
|
-
t.body === void 0 || t.body === null ? h = void 0 : o ||
|
|
69
|
-
const
|
|
68
|
+
t.body === void 0 || t.body === null ? h = void 0 : o || d || u || f ? h = t.body : (h = JSON.stringify(t.body), a.has("Content-Type") || a.set("Content-Type", "application/json"));
|
|
69
|
+
const y = this.customFetch ?? fetch;
|
|
70
70
|
let c;
|
|
71
71
|
try {
|
|
72
|
-
c = await
|
|
72
|
+
c = await y(s.toString(), {
|
|
73
73
|
method: t.method ?? "POST",
|
|
74
74
|
headers: a,
|
|
75
75
|
body: h,
|
|
@@ -78,7 +78,7 @@ class q {
|
|
|
78
78
|
});
|
|
79
79
|
} catch (p) {
|
|
80
80
|
const R = p instanceof Error ? p.message : String(p);
|
|
81
|
-
throw new
|
|
81
|
+
throw new n("network_error", `Network request failed: ${R}`, { cause: p });
|
|
82
82
|
}
|
|
83
83
|
if (c.status === 402) {
|
|
84
84
|
const p = await K(c);
|
|
@@ -86,14 +86,14 @@ class q {
|
|
|
86
86
|
}
|
|
87
87
|
if (!c.ok) {
|
|
88
88
|
const p = await $(c.clone());
|
|
89
|
-
throw new
|
|
89
|
+
throw new n(
|
|
90
90
|
p ?? `http_${c.status}`,
|
|
91
91
|
c.statusText || "Gateway request failed",
|
|
92
92
|
{ status: c.status }
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
|
-
const
|
|
96
|
-
return this.onChargeSuccess?.(
|
|
95
|
+
const g = c.headers.get("X-Query-Type") ?? void 0;
|
|
96
|
+
return this.onChargeSuccess?.(g), c;
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
async function K(i) {
|
|
@@ -149,8 +149,8 @@ const M = {
|
|
|
149
149
|
const e = chrome?.storage?.onChanged;
|
|
150
150
|
if (!e) return () => {
|
|
151
151
|
};
|
|
152
|
-
const s = (a,
|
|
153
|
-
if (
|
|
152
|
+
const s = (a, r) => {
|
|
153
|
+
if (r !== "local") return;
|
|
154
154
|
const o = a[i];
|
|
155
155
|
o && t(typeof o.newValue == "string" ? o.newValue : null);
|
|
156
156
|
};
|
|
@@ -195,10 +195,10 @@ const M = {
|
|
|
195
195
|
v.delete(i);
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
|
-
function
|
|
198
|
+
function L(i) {
|
|
199
199
|
return i || (F() ? M : typeof window < "u" && "localStorage" in window ? x : J);
|
|
200
200
|
}
|
|
201
|
-
const
|
|
201
|
+
const l = {
|
|
202
202
|
visitorId: "pw-visitor-id",
|
|
203
203
|
lastLoginMethod: (i) => `pw-${i}-last-login-method`,
|
|
204
204
|
lastLoginEmail: (i) => `pw-${i}-last-login-email`,
|
|
@@ -228,7 +228,7 @@ const y = {
|
|
|
228
228
|
// (оптимистично через `decrementBalanceLocal`).
|
|
229
229
|
balances: (i, t) => `pw-${i}-${t}-balances-v1`
|
|
230
230
|
};
|
|
231
|
-
function
|
|
231
|
+
function C() {
|
|
232
232
|
const i = typeof globalThis < "u" ? globalThis.crypto : void 0;
|
|
233
233
|
if (i && typeof i.randomUUID == "function") return i.randomUUID();
|
|
234
234
|
const t = new Uint8Array(16);
|
|
@@ -242,13 +242,13 @@ function N() {
|
|
|
242
242
|
}
|
|
243
243
|
async function I(i) {
|
|
244
244
|
try {
|
|
245
|
-
const e = await i.getItem(
|
|
245
|
+
const e = await i.getItem(l.visitorId);
|
|
246
246
|
if (e && typeof e == "string" && e.length >= 16) return e;
|
|
247
247
|
} catch {
|
|
248
248
|
}
|
|
249
|
-
const t =
|
|
249
|
+
const t = C();
|
|
250
250
|
try {
|
|
251
|
-
await i.setItem(
|
|
251
|
+
await i.setItem(l.visitorId, t);
|
|
252
252
|
} catch {
|
|
253
253
|
}
|
|
254
254
|
return t;
|
|
@@ -256,7 +256,8 @@ async function I(i) {
|
|
|
256
256
|
const H = 5e3, V = 30 * 6e4, b = 60 * 6e4, j = 5 * 6e4, _ = {
|
|
257
257
|
has_active_subscription: !1,
|
|
258
258
|
purchases: [],
|
|
259
|
-
trial: null
|
|
259
|
+
trial: null,
|
|
260
|
+
had_previous_trial: !1
|
|
260
261
|
};
|
|
261
262
|
function B(i) {
|
|
262
263
|
return i && (i.email || i.userId || i.anonymousId) || "guest";
|
|
@@ -272,12 +273,12 @@ function Q(i, t) {
|
|
|
272
273
|
if (i[e].type !== t[e].type || i[e].count !== t[e].count) return !1;
|
|
273
274
|
return !0;
|
|
274
275
|
}
|
|
275
|
-
class
|
|
276
|
+
class ut {
|
|
276
277
|
constructor(t) {
|
|
277
278
|
if (this.cachedBootstrap = null, this.cachedBootstrapAt = 0, this.inflightBootstrap = null, this.bootstrapListeners = /* @__PURE__ */ new Set(), this.bootstrapStorageUnwatch = null, this.authUnsubscribe = null, this.cachedUser = null, this.cachedUserAt = 0, this.inflightUser = null, this.userListeners = /* @__PURE__ */ new Set(), this.visitorIdPromise = null, this.visitorId = null, this.inflightCheckouts = /* @__PURE__ */ new Map(), this.cachedBalances = null, this.cachedBalancesAt = 0, this.balancesStorageUnwatch = null, this.inflightBalances = null, this.balanceListeners = /* @__PURE__ */ new Set(), this.previewVersionCounter = 0, !t.paywallId)
|
|
278
|
-
throw new
|
|
279
|
+
throw new n("invalid_config", "paywallId is required");
|
|
279
280
|
if (!t.apiOrigin)
|
|
280
|
-
throw new
|
|
281
|
+
throw new n(
|
|
281
282
|
"invalid_config",
|
|
282
283
|
'apiOrigin is required. Pass the paywall custom_domain configured in the platform (e.g. "https://pay.your-domain.com"). The legacy "appbox.space" fallback is not used in SDK 3.0.'
|
|
283
284
|
);
|
|
@@ -285,7 +286,7 @@ class lt {
|
|
|
285
286
|
const e = t.auth?.getCachedUser();
|
|
286
287
|
this.identity = t.identity ?? (e ? T(e) : void 0), this.apiKey = t.apiKey, this.fetchImpl = t.fetch, t.apiKey && typeof window < "u" && typeof window.document < "u" && console.error(
|
|
287
288
|
"[paywall] SECURITY: BillingClient.apiKey detected in browser context. This is a server-SDK key and exposes your account. Remove apiKey or move BillingClient to a trusted backend."
|
|
288
|
-
), this.storage =
|
|
289
|
+
), this.storage = L(t.storage), this.api = new E({
|
|
289
290
|
apiOrigin: this.apiOrigin,
|
|
290
291
|
paywallId: t.paywallId,
|
|
291
292
|
capabilities: t.capabilities,
|
|
@@ -295,8 +296,8 @@ class lt {
|
|
|
295
296
|
// Authorization-хедер просто не выставится.
|
|
296
297
|
getAuthToken: t.auth ? () => t.auth.getAccessToken() : void 0
|
|
297
298
|
}), t.auth && (this.authUnsubscribe = t.auth.onAuthChange((s, a) => {
|
|
298
|
-
const
|
|
299
|
-
W(this.identity,
|
|
299
|
+
const r = a ? T(a.user) : void 0;
|
|
300
|
+
W(this.identity, r) || this.setIdentity(r);
|
|
300
301
|
})), this.hydrateUserFromStorage(), this.hydrateBootstrapFromStorage(), this.subscribeBootstrapStorage(), this.hydrateBalancesFromStorage(), this.subscribeBalancesStorage(), this.visitorIdPromise = I(this.storage).then((s) => (this.visitorId = s, s));
|
|
301
302
|
}
|
|
302
303
|
/**
|
|
@@ -336,7 +337,7 @@ class lt {
|
|
|
336
337
|
const e = typeof t == "boolean" ? { force: t } : t;
|
|
337
338
|
if (this.previewMode) {
|
|
338
339
|
if (this.cachedBootstrap) return this.cachedBootstrap;
|
|
339
|
-
throw new
|
|
340
|
+
throw new n(
|
|
340
341
|
"invalid_config",
|
|
341
342
|
"BillingClient in preview mode but cachedBootstrap is not seeded. Call setBootstrap(bootstrap) before open()."
|
|
342
343
|
);
|
|
@@ -391,12 +392,12 @@ class lt {
|
|
|
391
392
|
offers: t.offers !== void 0 ? t.offers : e.offers,
|
|
392
393
|
version: `preview:${++this.previewVersionCounter}`
|
|
393
394
|
};
|
|
394
|
-
s.layout || (s.layout = U(s.settings, s.prices)),
|
|
395
|
+
s.layout || (s.layout = U(s.settings, s.prices)), w(s), this.cachedBootstrap = s, this.cachedBootstrapAt = Date.now();
|
|
395
396
|
for (const a of this.bootstrapListeners)
|
|
396
397
|
try {
|
|
397
398
|
a(s);
|
|
398
|
-
} catch (
|
|
399
|
-
console.warn("[paywall] onBootstrapChange listener threw",
|
|
399
|
+
} catch (r) {
|
|
400
|
+
console.warn("[paywall] onBootstrapChange listener threw", r);
|
|
400
401
|
}
|
|
401
402
|
}
|
|
402
403
|
// Network primitive — единая точка для force-запроса, revalidate'а и
|
|
@@ -412,8 +413,8 @@ class lt {
|
|
|
412
413
|
});
|
|
413
414
|
if ("unchanged" in a && a.unchanged)
|
|
414
415
|
return this.cachedBootstrap ? (this.cachedBootstrapAt = Date.now(), a.user && this.applyUser(a.user), this.cachedBootstrap) : this.fetchBootstrap({ signal: t.signal });
|
|
415
|
-
const
|
|
416
|
-
return Y(
|
|
416
|
+
const r = a;
|
|
417
|
+
return Y(r.settings.custom_domain, this.apiOrigin), r.layout || (r.layout = U(r.settings, r.prices)), w(r), this.applyBootstrap(r, { persist: !0 }), r.user && this.applyUser(r.user), r;
|
|
417
418
|
}
|
|
418
419
|
// Фоновый revalidate из stale-while-revalidate ветки. Дедуплицируется через
|
|
419
420
|
// `inflightBootstrap`, чтобы параллельные revalidate'ы не пересекались.
|
|
@@ -436,18 +437,18 @@ class lt {
|
|
|
436
437
|
for (const a of this.bootstrapListeners)
|
|
437
438
|
try {
|
|
438
439
|
a(t);
|
|
439
|
-
} catch (
|
|
440
|
-
console.warn("[paywall] onBootstrapChange listener threw",
|
|
440
|
+
} catch (r) {
|
|
441
|
+
console.warn("[paywall] onBootstrapChange listener threw", r);
|
|
441
442
|
}
|
|
442
443
|
}
|
|
443
444
|
async hydrateBootstrapFromStorage() {
|
|
444
445
|
if (!this.cachedBootstrap)
|
|
445
446
|
try {
|
|
446
|
-
const t = await this.storage.getItem(
|
|
447
|
+
const t = await this.storage.getItem(l.bootstrap(this.paywallId));
|
|
447
448
|
if (!t) return;
|
|
448
449
|
const e = JSON.parse(t);
|
|
449
450
|
if (!e?.bootstrap || Date.now() - e.at > b || this.cachedBootstrap) return;
|
|
450
|
-
|
|
451
|
+
w(e.bootstrap), this.cachedBootstrap = e.bootstrap, this.cachedBootstrapAt = e.at;
|
|
451
452
|
for (const s of this.bootstrapListeners)
|
|
452
453
|
try {
|
|
453
454
|
s(e.bootstrap);
|
|
@@ -462,7 +463,7 @@ class lt {
|
|
|
462
463
|
try {
|
|
463
464
|
const { user: e, ...s } = t;
|
|
464
465
|
await this.storage.setItem(
|
|
465
|
-
|
|
466
|
+
l.bootstrap(this.paywallId),
|
|
466
467
|
JSON.stringify({ at: Date.now(), bootstrap: s })
|
|
467
468
|
);
|
|
468
469
|
} catch {
|
|
@@ -473,7 +474,7 @@ class lt {
|
|
|
473
474
|
// no-op, всё работает как раньше через сеть.
|
|
474
475
|
subscribeBootstrapStorage() {
|
|
475
476
|
typeof this.storage.watch == "function" && (this.bootstrapStorageUnwatch = this.storage.watch(
|
|
476
|
-
|
|
477
|
+
l.bootstrap(this.paywallId),
|
|
477
478
|
(t) => {
|
|
478
479
|
if (t)
|
|
479
480
|
try {
|
|
@@ -483,7 +484,7 @@ class lt {
|
|
|
483
484
|
this.cachedBootstrapAt = e.at;
|
|
484
485
|
return;
|
|
485
486
|
}
|
|
486
|
-
|
|
487
|
+
w(e.bootstrap), this.applyBootstrap(e.bootstrap, { persist: !1 });
|
|
487
488
|
} catch {
|
|
488
489
|
}
|
|
489
490
|
}
|
|
@@ -530,7 +531,7 @@ class lt {
|
|
|
530
531
|
* есть `navigator.language`.
|
|
531
532
|
*/
|
|
532
533
|
getUserLanguage() {
|
|
533
|
-
const t = typeof navigator < "u" && navigator.language ? navigator.language : null, e = this.cachedBootstrap?.settings.locale_default ?? null, s = this.cachedBootstrap ?
|
|
534
|
+
const t = typeof navigator < "u" && navigator.language ? navigator.language : null, e = this.cachedBootstrap?.settings.locale_default ?? null, s = this.cachedBootstrap ? N(this.cachedBootstrap) : null;
|
|
534
535
|
return { tag: s ?? t ?? e, applied: s, browserLanguage: t, countryLanguage: e };
|
|
535
536
|
}
|
|
536
537
|
/**
|
|
@@ -581,8 +582,8 @@ class lt {
|
|
|
581
582
|
if (s === "sync")
|
|
582
583
|
try {
|
|
583
584
|
t(a);
|
|
584
|
-
} catch (
|
|
585
|
-
console.warn("[paywall] onUserChange initial sync threw",
|
|
585
|
+
} catch (r) {
|
|
586
|
+
console.warn("[paywall] onUserChange initial sync threw", r);
|
|
586
587
|
}
|
|
587
588
|
else
|
|
588
589
|
queueMicrotask(() => {
|
|
@@ -610,7 +611,7 @@ class lt {
|
|
|
610
611
|
}
|
|
611
612
|
}
|
|
612
613
|
storageKey() {
|
|
613
|
-
return
|
|
614
|
+
return l.userState(this.paywallId, B(this.identity));
|
|
614
615
|
}
|
|
615
616
|
async hydrateUserFromStorage() {
|
|
616
617
|
if (!this.cachedUser)
|
|
@@ -682,8 +683,8 @@ class lt {
|
|
|
682
683
|
if (s === "sync")
|
|
683
684
|
try {
|
|
684
685
|
t(a);
|
|
685
|
-
} catch (
|
|
686
|
-
console.warn("[paywall] onBalanceChange initial sync threw",
|
|
686
|
+
} catch (r) {
|
|
687
|
+
console.warn("[paywall] onBalanceChange initial sync threw", r);
|
|
687
688
|
}
|
|
688
689
|
else
|
|
689
690
|
queueMicrotask(() => {
|
|
@@ -714,10 +715,10 @@ class lt {
|
|
|
714
715
|
return;
|
|
715
716
|
}
|
|
716
717
|
if (!this.cachedBalances) return;
|
|
717
|
-
const e = this.cachedBalances.findIndex((
|
|
718
|
+
const e = this.cachedBalances.findIndex((r) => r.type === t);
|
|
718
719
|
if (e < 0 || this.cachedBalances[e].count <= 0) return;
|
|
719
720
|
const a = this.cachedBalances.map(
|
|
720
|
-
(
|
|
721
|
+
(r, o) => o === e ? { ...r, count: r.count - 1 } : r
|
|
721
722
|
);
|
|
722
723
|
this.applyBalances(a);
|
|
723
724
|
}
|
|
@@ -760,12 +761,12 @@ class lt {
|
|
|
760
761
|
for (const a of this.balanceListeners)
|
|
761
762
|
try {
|
|
762
763
|
a(t);
|
|
763
|
-
} catch (
|
|
764
|
-
console.warn("[paywall] onBalanceChange listener threw",
|
|
764
|
+
} catch (r) {
|
|
765
|
+
console.warn("[paywall] onBalanceChange listener threw", r);
|
|
765
766
|
}
|
|
766
767
|
}
|
|
767
768
|
balancesStorageKey() {
|
|
768
|
-
return
|
|
769
|
+
return l.balances(this.paywallId, B(this.identity));
|
|
769
770
|
}
|
|
770
771
|
async hydrateBalancesFromStorage() {
|
|
771
772
|
if (!this.cachedBalances)
|
|
@@ -812,42 +813,42 @@ class lt {
|
|
|
812
813
|
}
|
|
813
814
|
async createCheckout(t) {
|
|
814
815
|
if (!this.identity?.email)
|
|
815
|
-
throw new
|
|
816
|
+
throw new n(
|
|
816
817
|
"identity_required",
|
|
817
818
|
"createCheckout requires identity with email"
|
|
818
819
|
);
|
|
819
820
|
const e = t.idempotencyKey ?? `auto:${t.priceId}`, s = this.inflightCheckouts.get(e);
|
|
820
821
|
if (s) return s;
|
|
821
|
-
const
|
|
822
|
-
"Idempotency-Key": t.idempotencyKey ??
|
|
822
|
+
const r = {
|
|
823
|
+
"Idempotency-Key": t.idempotencyKey ?? C()
|
|
823
824
|
};
|
|
824
|
-
this.apiKey && (
|
|
825
|
-
const o = this.cachedBootstrap?.settings,
|
|
825
|
+
this.apiKey && (r["X-Api-Key"] = this.apiKey);
|
|
826
|
+
const o = this.cachedBootstrap?.settings, d = t.successUrl ?? o?.success_redirect_url ?? void 0, u = t.shopUrl ?? o?.checkout_shop_url ?? void 0, f = this.api.request(`/api/v1/paywall/${this.paywallId}/start-checkout`, {
|
|
826
827
|
method: "POST",
|
|
827
|
-
headers:
|
|
828
|
+
headers: r,
|
|
828
829
|
signal: t.signal,
|
|
829
830
|
body: JSON.stringify({
|
|
830
831
|
email: this.identity.email,
|
|
831
832
|
priceId: Number(t.priceId),
|
|
832
|
-
successUrl:
|
|
833
|
+
successUrl: d,
|
|
833
834
|
errorUrl: t.errorUrl,
|
|
834
|
-
shopUrl:
|
|
835
|
+
shopUrl: u,
|
|
835
836
|
productName: o?.checkout_product_name ?? void 0,
|
|
836
837
|
trial_days: t.trialDays,
|
|
837
838
|
ignoreActivePurchase: t.ignoreActivePurchase ? !0 : void 0,
|
|
838
839
|
userMeta: this.identity.userId ? { userId: this.identity.userId } : void 0
|
|
839
840
|
})
|
|
840
841
|
}).then((h) => ({ url: h.checkoutUrl, acquiring: h.acquiring })).catch((h) => {
|
|
841
|
-
throw h instanceof
|
|
842
|
+
throw h instanceof n && h.status === 409 && h.cause && typeof h.cause == "object" && h.cause.hasActivePurchase === !0 ? new n(
|
|
842
843
|
"already_purchased",
|
|
843
844
|
"You already have an active subscription",
|
|
844
845
|
{ status: 409, cause: h.cause }
|
|
845
846
|
) : h;
|
|
846
847
|
});
|
|
847
|
-
return this.inflightCheckouts.set(e,
|
|
848
|
-
this.inflightCheckouts.get(e) ===
|
|
848
|
+
return this.inflightCheckouts.set(e, f), f.finally(() => {
|
|
849
|
+
this.inflightCheckouts.get(e) === f && this.inflightCheckouts.delete(e);
|
|
849
850
|
}).catch(() => {
|
|
850
|
-
}),
|
|
851
|
+
}), f;
|
|
851
852
|
}
|
|
852
853
|
/**
|
|
853
854
|
* URL Stripe/Paddle/Chargebee customer portal — место, где залогиненный
|
|
@@ -867,7 +868,7 @@ class lt {
|
|
|
867
868
|
*/
|
|
868
869
|
async getCustomerPortalUrl(t = {}) {
|
|
869
870
|
if (!this.auth && !this.apiKey && !this.identity?.email)
|
|
870
|
-
throw new
|
|
871
|
+
throw new n(
|
|
871
872
|
"identity_required",
|
|
872
873
|
"getCustomerPortalUrl requires auth, apiKey, or identity.email"
|
|
873
874
|
);
|
|
@@ -899,7 +900,7 @@ class lt {
|
|
|
899
900
|
*/
|
|
900
901
|
async listPurchases(t = {}) {
|
|
901
902
|
if (!this.auth)
|
|
902
|
-
throw new
|
|
903
|
+
throw new n(
|
|
903
904
|
"auth_required",
|
|
904
905
|
"listPurchases requires AuthClient (Bearer auth)"
|
|
905
906
|
);
|
|
@@ -920,7 +921,7 @@ class lt {
|
|
|
920
921
|
*/
|
|
921
922
|
async cancelSubscription(t) {
|
|
922
923
|
if (!this.auth)
|
|
923
|
-
throw new
|
|
924
|
+
throw new n(
|
|
924
925
|
"auth_required",
|
|
925
926
|
"cancelSubscription requires AuthClient (Bearer auth)"
|
|
926
927
|
);
|
|
@@ -945,12 +946,12 @@ class lt {
|
|
|
945
946
|
async createSupportTicket(t) {
|
|
946
947
|
const e = t.email ?? this.identity?.email ?? null, s = `/api/v1/paywall/${this.paywallId}/support/ticket`;
|
|
947
948
|
if (!!t.files && t.files.length > 0) {
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
for (const o of t.files)
|
|
949
|
+
const r = new FormData();
|
|
950
|
+
r.set("subject", t.subject), r.set("content", t.content), e && r.set("customer_email", e);
|
|
951
|
+
for (const o of t.files) r.append("files", o);
|
|
951
952
|
return this.api.request(s, {
|
|
952
953
|
method: "POST",
|
|
953
|
-
body:
|
|
954
|
+
body: r
|
|
954
955
|
});
|
|
955
956
|
}
|
|
956
957
|
return this.api.request(s, {
|
|
@@ -982,7 +983,7 @@ function O(i) {
|
|
|
982
983
|
function Y(i, t) {
|
|
983
984
|
const e = O(i);
|
|
984
985
|
if (!(!e || O(t) === e))
|
|
985
|
-
throw new
|
|
986
|
+
throw new n(
|
|
986
987
|
"invalid_config",
|
|
987
988
|
`apiOrigin mismatch: SDK initialized with "${t}" but paywall is configured with custom_domain "${i}". Use the custom_domain from the platform paywall settings.`
|
|
988
989
|
);
|
|
@@ -991,15 +992,18 @@ function U(i, t) {
|
|
|
991
992
|
return {
|
|
992
993
|
type: "modal",
|
|
993
994
|
blocks: [
|
|
995
|
+
// offer_banner НЕ в default layout — PaywallRoot рендерит его как
|
|
996
|
+
// top-tab над dialog'ом (rounded-top, negative margin), за пределами
|
|
997
|
+
// scrollable area. Блок остаётся в registry для opt-in inline-вариантa.
|
|
994
998
|
{ type: "heading", text: i.name || "Upgrade", level: 1 },
|
|
995
999
|
{ type: "price_grid", priceIds: t.map((e) => e.id) },
|
|
996
|
-
{ type: "cta_button",
|
|
1000
|
+
{ type: "cta_button", action: "checkout" },
|
|
997
1001
|
{ type: "guarantee_badge" },
|
|
998
1002
|
{ type: "current_session" }
|
|
999
1003
|
]
|
|
1000
1004
|
};
|
|
1001
1005
|
}
|
|
1002
|
-
function
|
|
1006
|
+
function N(i) {
|
|
1003
1007
|
const t = i.locales;
|
|
1004
1008
|
if (!t) return null;
|
|
1005
1009
|
const e = [];
|
|
@@ -1014,15 +1018,15 @@ function L(i) {
|
|
|
1014
1018
|
if (a && Object.prototype.hasOwnProperty.call(t, a)) return a;
|
|
1015
1019
|
return null;
|
|
1016
1020
|
}
|
|
1017
|
-
function
|
|
1018
|
-
const t =
|
|
1021
|
+
function w(i) {
|
|
1022
|
+
const t = N(i);
|
|
1019
1023
|
if (!t) return;
|
|
1020
1024
|
const e = i.locales?.[t];
|
|
1021
1025
|
e && (e.layout && (i.layout = e.layout), e.prices && (i.prices = i.prices.map((s) => {
|
|
1022
1026
|
const a = e.prices?.[s.id];
|
|
1023
1027
|
if (!a) return s;
|
|
1024
|
-
const
|
|
1025
|
-
return "label" in a && (
|
|
1028
|
+
const r = { ...s };
|
|
1029
|
+
return "label" in a && (r.label = a.label ?? null), "description" in a && (r.description = a.description ?? null), r;
|
|
1026
1030
|
})));
|
|
1027
1031
|
}
|
|
1028
1032
|
function P(i) {
|
|
@@ -1052,16 +1056,16 @@ function et() {
|
|
|
1052
1056
|
return S(P(16));
|
|
1053
1057
|
}
|
|
1054
1058
|
const st = 6e4, it = 600 * 1e3;
|
|
1055
|
-
class
|
|
1059
|
+
class dt {
|
|
1056
1060
|
constructor(t) {
|
|
1057
1061
|
if (this.session = null, this.inflightRefresh = null, this.inflightAnonSignin = null, this.listeners = /* @__PURE__ */ new Set(), this.storageUnwatch = null, this.destroyed = !1, this.oauthFlows = /* @__PURE__ */ new Map(), !t.paywallId)
|
|
1058
|
-
throw new
|
|
1062
|
+
throw new n("invalid_config", "paywallId is required");
|
|
1059
1063
|
if (!t.apiOrigin)
|
|
1060
|
-
throw new
|
|
1064
|
+
throw new n(
|
|
1061
1065
|
"invalid_config",
|
|
1062
1066
|
"apiOrigin is required. Pass the paywall custom_domain configured in the platform."
|
|
1063
1067
|
);
|
|
1064
|
-
this.paywallId = t.paywallId, this.apiOrigin = t.apiOrigin, this.storage =
|
|
1068
|
+
this.paywallId = t.paywallId, this.apiOrigin = t.apiOrigin, this.storage = L(t.storage), this.api = new E({
|
|
1065
1069
|
apiOrigin: this.apiOrigin,
|
|
1066
1070
|
paywallId: t.paywallId,
|
|
1067
1071
|
fetch: t.fetch
|
|
@@ -1151,8 +1155,8 @@ class ut {
|
|
|
1151
1155
|
user_meta: t.userMeta
|
|
1152
1156
|
})
|
|
1153
1157
|
}
|
|
1154
|
-
),
|
|
1155
|
-
return this.setSession(
|
|
1158
|
+
), r = this.toSession(a, a.user);
|
|
1159
|
+
return this.setSession(r, { event: "SIGNED_IN" }), this.recordLastLogin("email", t.email), r;
|
|
1156
1160
|
}
|
|
1157
1161
|
/**
|
|
1158
1162
|
* Signup. Если в Supabase включён email confirm — сервер возвращает
|
|
@@ -1178,9 +1182,9 @@ class ut {
|
|
|
1178
1182
|
}
|
|
1179
1183
|
);
|
|
1180
1184
|
if (a.status === "confirmation_required")
|
|
1181
|
-
return { kind: "confirmation_required", user: a.user };
|
|
1182
|
-
const
|
|
1183
|
-
return this.setSession(
|
|
1185
|
+
return this.recordLastLogin("email", t.email), { kind: "confirmation_required", user: a.user };
|
|
1186
|
+
const r = this.toSession(a, a.user);
|
|
1187
|
+
return this.setSession(r, { event: "SIGNED_IN" }), this.recordLastLogin("email", t.email), { kind: "signed_in", session: r };
|
|
1184
1188
|
}
|
|
1185
1189
|
/**
|
|
1186
1190
|
* Повторная отправка confirmation-email после signUp с включённым
|
|
@@ -1243,8 +1247,8 @@ class ut {
|
|
|
1243
1247
|
user_meta: t.userMeta
|
|
1244
1248
|
})
|
|
1245
1249
|
}
|
|
1246
|
-
), a = this.toSession(s, s.user),
|
|
1247
|
-
return this.setSession(a, { event:
|
|
1250
|
+
), a = this.toSession(s, s.user), r = t.type === "recovery" ? "PASSWORD_RECOVERY" : "SIGNED_IN";
|
|
1251
|
+
return this.setSession(a, { event: r }), a;
|
|
1248
1252
|
}
|
|
1249
1253
|
/**
|
|
1250
1254
|
* Запрос recovery email. Бэк всегда ok, чтобы не палить enumeration.
|
|
@@ -1270,7 +1274,7 @@ class ut {
|
|
|
1270
1274
|
await this.hydrated;
|
|
1271
1275
|
const e = await this.getAccessToken();
|
|
1272
1276
|
if (!e)
|
|
1273
|
-
throw new
|
|
1277
|
+
throw new n("not_authenticated", "no active session");
|
|
1274
1278
|
await this.api.request(
|
|
1275
1279
|
`/api/v1/paywall/${this.paywallId}/auth/password/update`,
|
|
1276
1280
|
{
|
|
@@ -1335,8 +1339,8 @@ class ut {
|
|
|
1335
1339
|
...s.user,
|
|
1336
1340
|
email: s.user.email ?? null,
|
|
1337
1341
|
is_anonymous: !0
|
|
1338
|
-
},
|
|
1339
|
-
return this.setSession(
|
|
1342
|
+
}, r = this.toSession(s, a);
|
|
1343
|
+
return this.setSession(r, { event: "SIGNED_IN" }), await this.writeAnonRefreshToken(r.refresh_token), r;
|
|
1340
1344
|
})();
|
|
1341
1345
|
try {
|
|
1342
1346
|
return await this.inflightAnonSignin;
|
|
@@ -1360,7 +1364,7 @@ class ut {
|
|
|
1360
1364
|
), s = this.session?.user.is_anonymous === !0 ? this.session.user : { id: "", email: null, is_anonymous: !0 }, a = this.toSession(e, s);
|
|
1361
1365
|
return this.setSession(a, { event: "SIGNED_IN" }), await this.writeAnonRefreshToken(a.refresh_token), a;
|
|
1362
1366
|
} catch (e) {
|
|
1363
|
-
if (e instanceof
|
|
1367
|
+
if (e instanceof n && e.status === 401)
|
|
1364
1368
|
return await this.clearAnonRefreshToken(), null;
|
|
1365
1369
|
throw e;
|
|
1366
1370
|
}
|
|
@@ -1390,7 +1394,7 @@ class ut {
|
|
|
1390
1394
|
await this.hydrated;
|
|
1391
1395
|
const e = await this.getAccessToken();
|
|
1392
1396
|
if (!e)
|
|
1393
|
-
throw new
|
|
1397
|
+
throw new n("not_authenticated", "no active session");
|
|
1394
1398
|
const s = {
|
|
1395
1399
|
Authorization: `Bearer ${e}`
|
|
1396
1400
|
};
|
|
@@ -1409,19 +1413,19 @@ class ut {
|
|
|
1409
1413
|
);
|
|
1410
1414
|
if (a.status === "confirmation_required")
|
|
1411
1415
|
return { kind: "confirmation_required", email: a.email };
|
|
1412
|
-
const
|
|
1413
|
-
if (!
|
|
1414
|
-
throw new
|
|
1416
|
+
const r = this.session;
|
|
1417
|
+
if (!r)
|
|
1418
|
+
throw new n(
|
|
1415
1419
|
"not_authenticated",
|
|
1416
1420
|
"session disappeared during upgrade"
|
|
1417
1421
|
);
|
|
1418
1422
|
const o = {
|
|
1419
|
-
...
|
|
1423
|
+
...r.user,
|
|
1420
1424
|
id: a.user.id,
|
|
1421
1425
|
email: a.user.email,
|
|
1422
1426
|
is_anonymous: a.user.is_anonymous ?? !1
|
|
1423
|
-
},
|
|
1424
|
-
return this.setSession(
|
|
1427
|
+
}, d = { ...r, user: o };
|
|
1428
|
+
return this.setSession(d, { event: "USER_UPDATED" }), await this.clearAnonRefreshToken(), { kind: "updated", session: d };
|
|
1425
1429
|
}
|
|
1426
1430
|
/**
|
|
1427
1431
|
* OAuth signin через popup с PKCE. Жизненный цикл:
|
|
@@ -1445,22 +1449,22 @@ class ut {
|
|
|
1445
1449
|
*/
|
|
1446
1450
|
async signInWithOAuth(t) {
|
|
1447
1451
|
if (typeof window > "u")
|
|
1448
|
-
throw new
|
|
1452
|
+
throw new n("oauth_unavailable", "window is required for OAuth");
|
|
1449
1453
|
const { authorize_url: e, state: s } = await this.startOAuthFlow({
|
|
1450
1454
|
provider: t.provider,
|
|
1451
1455
|
scopes: t.scopes,
|
|
1452
1456
|
userMeta: t.userMeta
|
|
1453
1457
|
}), a = this.openPopup(e, `pw-oauth-${s}`);
|
|
1454
1458
|
if (!a)
|
|
1455
|
-
throw this.oauthFlows.delete(s), new
|
|
1459
|
+
throw this.oauthFlows.delete(s), new n(
|
|
1456
1460
|
"popup_blocked",
|
|
1457
1461
|
"browser blocked auth popup — call from a user gesture"
|
|
1458
1462
|
);
|
|
1459
1463
|
t.onPopupOpened?.();
|
|
1460
|
-
const
|
|
1464
|
+
const r = await nt(a, s);
|
|
1461
1465
|
if (this.destroyed)
|
|
1462
|
-
throw this.oauthFlows.delete(s), new
|
|
1463
|
-
return this.completeOAuthFlow({ state: s, code:
|
|
1466
|
+
throw this.oauthFlows.delete(s), new n("aborted", "AuthClient destroyed mid-flow");
|
|
1467
|
+
return this.completeOAuthFlow({ state: s, code: r });
|
|
1464
1468
|
}
|
|
1465
1469
|
/**
|
|
1466
1470
|
* Шаг 1 OAuth split-API: инициирует flow на бэке, генерит PKCE verifier
|
|
@@ -1478,13 +1482,13 @@ class ut {
|
|
|
1478
1482
|
*/
|
|
1479
1483
|
async startOAuthFlow(t) {
|
|
1480
1484
|
await this.hydrated, this.gcOAuthFlows();
|
|
1481
|
-
const e = Z(), s = await tt(e), a = et(),
|
|
1482
|
-
o && (
|
|
1483
|
-
const { authorize_url:
|
|
1485
|
+
const e = Z(), s = await tt(e), a = et(), r = {}, o = await this.getAccessToken().catch(() => null);
|
|
1486
|
+
o && (r.Authorization = `Bearer ${o}`);
|
|
1487
|
+
const { authorize_url: d } = await this.api.request(
|
|
1484
1488
|
`/api/v1/paywall/${this.paywallId}/auth/oauth/init`,
|
|
1485
1489
|
{
|
|
1486
1490
|
method: "POST",
|
|
1487
|
-
headers: Object.keys(
|
|
1491
|
+
headers: Object.keys(r).length ? r : void 0,
|
|
1488
1492
|
body: JSON.stringify({
|
|
1489
1493
|
provider: t.provider,
|
|
1490
1494
|
code_challenge: s,
|
|
@@ -1496,8 +1500,9 @@ class ut {
|
|
|
1496
1500
|
return this.oauthFlows.set(a, {
|
|
1497
1501
|
verifier: e,
|
|
1498
1502
|
userMeta: t.userMeta,
|
|
1503
|
+
provider: t.provider,
|
|
1499
1504
|
startedAt: Date.now()
|
|
1500
|
-
}), { authorize_url:
|
|
1505
|
+
}), this.recordLastLoginMethod(t.provider), { authorize_url: d, state: a };
|
|
1501
1506
|
}
|
|
1502
1507
|
/**
|
|
1503
1508
|
* Шаг 2 OAuth split-API: обменивает code (полученный из popup) на session,
|
|
@@ -1512,7 +1517,7 @@ class ut {
|
|
|
1512
1517
|
await this.hydrated;
|
|
1513
1518
|
const e = this.oauthFlows.get(t.state);
|
|
1514
1519
|
if (!e)
|
|
1515
|
-
throw new
|
|
1520
|
+
throw new n(
|
|
1516
1521
|
"oauth_invalid_state",
|
|
1517
1522
|
"OAuth flow not found — start with startOAuthFlow first or check TTL"
|
|
1518
1523
|
);
|
|
@@ -1530,9 +1535,9 @@ class ut {
|
|
|
1530
1535
|
}
|
|
1531
1536
|
);
|
|
1532
1537
|
if (this.destroyed)
|
|
1533
|
-
throw new
|
|
1534
|
-
const
|
|
1535
|
-
return this.setSession(
|
|
1538
|
+
throw new n("aborted", "AuthClient destroyed mid-flow");
|
|
1539
|
+
const r = this.toSession(a, a.user);
|
|
1540
|
+
return this.setSession(r, { event: "SIGNED_IN" }), r.user.email && this.recordLastLoginEmail(r.user.email), r;
|
|
1536
1541
|
}
|
|
1537
1542
|
gcOAuthFlows() {
|
|
1538
1543
|
const t = Date.now() - it;
|
|
@@ -1563,7 +1568,7 @@ class ut {
|
|
|
1563
1568
|
), a = this.toSession(s, e);
|
|
1564
1569
|
return this.setSession(a, { event: "TOKEN_REFRESHED" }), e.is_anonymous === !0 && await this.writeAnonRefreshToken(a.refresh_token), a;
|
|
1565
1570
|
} catch (s) {
|
|
1566
|
-
if (s instanceof
|
|
1571
|
+
if (s instanceof n && s.status === 401)
|
|
1567
1572
|
return e.is_anonymous === !0 && await this.clearAnonRefreshToken(), this.setSession(null, { event: "SIGNED_OUT" }), null;
|
|
1568
1573
|
throw s;
|
|
1569
1574
|
} finally {
|
|
@@ -1590,7 +1595,7 @@ class ut {
|
|
|
1590
1595
|
await this.hydrated;
|
|
1591
1596
|
const t = this.session?.access_token;
|
|
1592
1597
|
if (!t)
|
|
1593
|
-
throw new
|
|
1598
|
+
throw new n("not_authenticated", "no active session");
|
|
1594
1599
|
await this.api.request(
|
|
1595
1600
|
`/api/v1/paywall/${this.paywallId}/auth/revoke-all`,
|
|
1596
1601
|
{
|
|
@@ -1673,7 +1678,7 @@ class ut {
|
|
|
1673
1678
|
setSession(t, e) {
|
|
1674
1679
|
if (this.destroyed) return;
|
|
1675
1680
|
const s = this.session;
|
|
1676
|
-
this.session = t, e.skipPersist || this.persist(),
|
|
1681
|
+
this.session = t, e.skipPersist || this.persist(), ht(s, t) || this.emit(e.event);
|
|
1677
1682
|
}
|
|
1678
1683
|
emit(t) {
|
|
1679
1684
|
for (const e of this.listeners)
|
|
@@ -1684,7 +1689,7 @@ class ut {
|
|
|
1684
1689
|
}
|
|
1685
1690
|
}
|
|
1686
1691
|
storageKey() {
|
|
1687
|
-
return
|
|
1692
|
+
return l.authSession(this.paywallId);
|
|
1688
1693
|
}
|
|
1689
1694
|
async hydrate() {
|
|
1690
1695
|
try {
|
|
@@ -1738,7 +1743,7 @@ class ut {
|
|
|
1738
1743
|
}
|
|
1739
1744
|
async readAnonRefreshToken() {
|
|
1740
1745
|
try {
|
|
1741
|
-
const t = await this.storage.getItem(
|
|
1746
|
+
const t = await this.storage.getItem(l.anonRefreshToken(this.paywallId));
|
|
1742
1747
|
return typeof t == "string" && t.length > 0 ? t : null;
|
|
1743
1748
|
} catch {
|
|
1744
1749
|
return null;
|
|
@@ -1747,7 +1752,7 @@ class ut {
|
|
|
1747
1752
|
async writeAnonRefreshToken(t) {
|
|
1748
1753
|
try {
|
|
1749
1754
|
await this.storage.setItem(
|
|
1750
|
-
|
|
1755
|
+
l.anonRefreshToken(this.paywallId),
|
|
1751
1756
|
t
|
|
1752
1757
|
);
|
|
1753
1758
|
} catch {
|
|
@@ -1756,11 +1761,41 @@ class ut {
|
|
|
1756
1761
|
async clearAnonRefreshToken() {
|
|
1757
1762
|
try {
|
|
1758
1763
|
await this.storage.removeItem(
|
|
1759
|
-
|
|
1764
|
+
l.anonRefreshToken(this.paywallId)
|
|
1760
1765
|
);
|
|
1761
1766
|
} catch {
|
|
1762
1767
|
}
|
|
1763
1768
|
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Last-used auth method + email — для UI бейджа "Last used" и pre-fill'а
|
|
1771
|
+
* email-инпута. Storage paywall-scoped, поэтому переключение между
|
|
1772
|
+
* пейволами на одном host'е не пересекает данные. Чтение всегда возвращает
|
|
1773
|
+
* объект — отсутствующие поля = null. */
|
|
1774
|
+
async getLastLogin() {
|
|
1775
|
+
try {
|
|
1776
|
+
const [t, e] = await Promise.all([
|
|
1777
|
+
this.storage.getItem(l.lastLoginMethod(this.paywallId)),
|
|
1778
|
+
this.storage.getItem(l.lastLoginEmail(this.paywallId))
|
|
1779
|
+
]);
|
|
1780
|
+
return !t || !ot(t) ? null : { method: t, email: typeof e == "string" && e ? e : null };
|
|
1781
|
+
} catch {
|
|
1782
|
+
return null;
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
/** Запись method и email атомарно (для email/password flows — оба известны
|
|
1786
|
+
* на момент signin/signup'а). OAuth-flows используют раздельные
|
|
1787
|
+
* recordLastLoginMethod (до popup) и recordLastLoginEmail (после exchange). */
|
|
1788
|
+
recordLastLogin(t, e) {
|
|
1789
|
+
this.recordLastLoginMethod(t), e && this.recordLastLoginEmail(e);
|
|
1790
|
+
}
|
|
1791
|
+
recordLastLoginMethod(t) {
|
|
1792
|
+
this.storage.setItem(l.lastLoginMethod(this.paywallId), t).catch(() => {
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
recordLastLoginEmail(t) {
|
|
1796
|
+
this.storage.setItem(l.lastLoginEmail(this.paywallId), t).catch(() => {
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1764
1799
|
/**
|
|
1765
1800
|
* Читает stable visitor_id из storage если он там уже есть. НЕ генерит:
|
|
1766
1801
|
* AuthClient может быть инстанцирован раньше BillingClient, а синтетический
|
|
@@ -1770,71 +1805,74 @@ class ut {
|
|
|
1770
1805
|
*/
|
|
1771
1806
|
async readVisitorId() {
|
|
1772
1807
|
try {
|
|
1773
|
-
const t = await this.storage.getItem(
|
|
1808
|
+
const t = await this.storage.getItem(l.visitorId);
|
|
1774
1809
|
return typeof t == "string" && t.length >= 16 ? t : void 0;
|
|
1775
1810
|
} catch {
|
|
1776
1811
|
return;
|
|
1777
1812
|
}
|
|
1778
1813
|
}
|
|
1779
1814
|
}
|
|
1780
|
-
const at = 5 * 6e4,
|
|
1781
|
-
function
|
|
1815
|
+
const at = 5 * 6e4, rt = 500;
|
|
1816
|
+
function nt(i, t) {
|
|
1782
1817
|
return new Promise((e, s) => {
|
|
1783
1818
|
let a = !1;
|
|
1784
|
-
const
|
|
1785
|
-
a = !0, window.removeEventListener("message", o), clearInterval(
|
|
1786
|
-
}, o = (
|
|
1819
|
+
const r = () => {
|
|
1820
|
+
a = !0, window.removeEventListener("message", o), clearInterval(d), clearTimeout(u);
|
|
1821
|
+
}, o = (f) => {
|
|
1787
1822
|
if (a) return;
|
|
1788
|
-
const h =
|
|
1823
|
+
const h = f.data;
|
|
1789
1824
|
if (!(!h || h.type !== "pw-oauth") && h.messageId === t) {
|
|
1790
1825
|
if (h.status === "success" && h.code) {
|
|
1791
|
-
|
|
1826
|
+
r();
|
|
1792
1827
|
try {
|
|
1793
1828
|
i.close();
|
|
1794
1829
|
} catch {
|
|
1795
1830
|
}
|
|
1796
1831
|
e(h.code);
|
|
1797
1832
|
} else if (h.status === "error") {
|
|
1798
|
-
|
|
1833
|
+
r();
|
|
1799
1834
|
try {
|
|
1800
1835
|
i.close();
|
|
1801
1836
|
} catch {
|
|
1802
1837
|
}
|
|
1803
1838
|
s(
|
|
1804
|
-
new
|
|
1839
|
+
new n(
|
|
1805
1840
|
"oauth_failed",
|
|
1806
1841
|
h.description || h.error || "OAuth provider returned error"
|
|
1807
1842
|
)
|
|
1808
1843
|
);
|
|
1809
1844
|
}
|
|
1810
1845
|
}
|
|
1811
|
-
},
|
|
1846
|
+
}, d = setInterval(() => {
|
|
1812
1847
|
if (a) return;
|
|
1813
|
-
let
|
|
1848
|
+
let f;
|
|
1814
1849
|
try {
|
|
1815
|
-
|
|
1850
|
+
f = i.closed;
|
|
1816
1851
|
} catch {
|
|
1817
1852
|
return;
|
|
1818
1853
|
}
|
|
1819
|
-
|
|
1820
|
-
},
|
|
1854
|
+
f && (r(), s(new n("oauth_cancelled", "auth popup was closed")));
|
|
1855
|
+
}, rt), u = setTimeout(() => {
|
|
1821
1856
|
if (!a) {
|
|
1822
|
-
|
|
1857
|
+
r();
|
|
1823
1858
|
try {
|
|
1824
1859
|
i.close();
|
|
1825
1860
|
} catch {
|
|
1826
1861
|
}
|
|
1827
|
-
s(new
|
|
1862
|
+
s(new n("oauth_timeout", "OAuth flow timed out"));
|
|
1828
1863
|
}
|
|
1829
1864
|
}, at);
|
|
1830
1865
|
window.addEventListener("message", o);
|
|
1831
1866
|
});
|
|
1832
1867
|
}
|
|
1833
|
-
function ot(i
|
|
1868
|
+
function ot(i) {
|
|
1869
|
+
return i === "google" || i === "apple" || i === "github" || i === "facebook" || i === "email";
|
|
1870
|
+
}
|
|
1871
|
+
function ht(i, t) {
|
|
1834
1872
|
return i === t ? !0 : !i || !t ? !1 : i.access_token === t.access_token && i.refresh_token === t.refresh_token && i.expires_at === t.expires_at && i.user.id === t.user.id && i.user.email === t.user.email;
|
|
1835
1873
|
}
|
|
1836
|
-
const
|
|
1837
|
-
class
|
|
1874
|
+
const ct = 1500, lt = 20, k = 200;
|
|
1875
|
+
class ft {
|
|
1838
1876
|
constructor(t) {
|
|
1839
1877
|
this.buffer = [], this.flushTimer = null, this.destroyed = !1, this.unloadHandler = null, this.visibilityHandler = null, this.opts = t, this.isEnabled() && this.attachUnloadHandlers();
|
|
1840
1878
|
}
|
|
@@ -1844,7 +1882,7 @@ class dt {
|
|
|
1844
1882
|
track(t, e) {
|
|
1845
1883
|
if (this.destroyed || !this.isEnabled() || typeof t != "string" || t.length === 0) return;
|
|
1846
1884
|
this.buffer.push({ type: t, ts: Date.now(), props: e });
|
|
1847
|
-
const s = this.opts.maxBufferSize ??
|
|
1885
|
+
const s = this.opts.maxBufferSize ?? lt;
|
|
1848
1886
|
if (this.buffer.length >= s) {
|
|
1849
1887
|
this.flush();
|
|
1850
1888
|
return;
|
|
@@ -1853,7 +1891,7 @@ class dt {
|
|
|
1853
1891
|
}
|
|
1854
1892
|
scheduleFlush() {
|
|
1855
1893
|
if (this.flushTimer || this.destroyed) return;
|
|
1856
|
-
const t = this.opts.flushIntervalMs ??
|
|
1894
|
+
const t = this.opts.flushIntervalMs ?? ct;
|
|
1857
1895
|
this.flushTimer = setTimeout(() => {
|
|
1858
1896
|
this.flushTimer = null, this.flush();
|
|
1859
1897
|
}, t);
|
|
@@ -1864,9 +1902,9 @@ class dt {
|
|
|
1864
1902
|
const t = this.buffer;
|
|
1865
1903
|
this.buffer = [];
|
|
1866
1904
|
try {
|
|
1867
|
-
const e = await this.opts.getVisitorId(), s = this.opts.getUserId?.() ?? null, a = JSON.stringify({ events: t }),
|
|
1868
|
-
if (!
|
|
1869
|
-
await
|
|
1905
|
+
const e = await this.opts.getVisitorId(), s = this.opts.getUserId?.() ?? null, a = JSON.stringify({ events: t }), r = this.opts.fetch ?? (typeof fetch < "u" ? fetch : void 0);
|
|
1906
|
+
if (!r) return;
|
|
1907
|
+
await r(this.opts.endpoint, {
|
|
1870
1908
|
method: "POST",
|
|
1871
1909
|
credentials: "omit",
|
|
1872
1910
|
keepalive: !0,
|
|
@@ -1900,13 +1938,13 @@ class dt {
|
|
|
1900
1938
|
sdk_version: m,
|
|
1901
1939
|
paywall_id: this.opts.paywallId,
|
|
1902
1940
|
capabilities: this.opts.capabilities?.join(",") ?? ""
|
|
1903
|
-
}),
|
|
1904
|
-
if (!
|
|
1941
|
+
}), r = this.opts.sendBeacon ?? (typeof navigator < "u" && typeof navigator.sendBeacon == "function" ? navigator.sendBeacon.bind(navigator) : null);
|
|
1942
|
+
if (!r) {
|
|
1905
1943
|
this.buffer.unshift(...t), this.flush();
|
|
1906
1944
|
return;
|
|
1907
1945
|
}
|
|
1908
1946
|
try {
|
|
1909
|
-
|
|
1947
|
+
r(this.opts.endpoint, a) || (this.buffer.unshift(...t), this.flush());
|
|
1910
1948
|
} catch {
|
|
1911
1949
|
this.buffer.unshift(...t), this.flush();
|
|
1912
1950
|
}
|
|
@@ -1935,15 +1973,15 @@ class dt {
|
|
|
1935
1973
|
export {
|
|
1936
1974
|
E as ApiClient,
|
|
1937
1975
|
q as ApiGatewayClient,
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1976
|
+
dt as AuthClient,
|
|
1977
|
+
ut as BillingClient,
|
|
1978
|
+
ft as EventTracker,
|
|
1979
|
+
n as PaywallError,
|
|
1942
1980
|
D as QuotaExceededError,
|
|
1943
1981
|
m as SDK_VERSION,
|
|
1944
|
-
|
|
1945
|
-
|
|
1982
|
+
l as STORAGE_KEYS,
|
|
1983
|
+
L as createStorage,
|
|
1946
1984
|
I as ensureVisitorId,
|
|
1947
|
-
|
|
1985
|
+
C as generateVisitorId
|
|
1948
1986
|
};
|
|
1949
1987
|
//# sourceMappingURL=core.js.map
|