@viceme-ai/sdk 0.6.2 → 0.8.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.
Files changed (44) hide show
  1. package/README.md +65 -17
  2. package/dist/capability-mount.d.ts +2 -0
  3. package/dist/capability-mount.d.ts.map +1 -1
  4. package/dist/chunks/client-DbPCnwf-.js +1471 -0
  5. package/dist/chunks/client-DbPCnwf-.js.map +1 -0
  6. package/dist/chunks/integration-CTsnJ8mN.js +38 -0
  7. package/dist/chunks/integration-CTsnJ8mN.js.map +1 -0
  8. package/dist/chunks/version-DXLLix7K.js +6 -0
  9. package/dist/chunks/{version-BJiUVcir.js.map → version-DXLLix7K.js.map} +1 -1
  10. package/dist/core/access-bridge.d.ts +17 -0
  11. package/dist/core/access-bridge.d.ts.map +1 -0
  12. package/dist/core/capabilities.d.ts +12 -2
  13. package/dist/core/capabilities.d.ts.map +1 -1
  14. package/dist/core/client.d.ts.map +1 -1
  15. package/dist/core/presentation.d.ts +10 -1
  16. package/dist/core/presentation.d.ts.map +1 -1
  17. package/dist/danmaku/mount.d.ts.map +1 -1
  18. package/dist/danmaku.js +117 -91
  19. package/dist/danmaku.js.map +1 -1
  20. package/dist/engagement/integration.d.ts +15 -0
  21. package/dist/engagement/integration.d.ts.map +1 -0
  22. package/dist/generated/public-contract.d.ts +260 -12
  23. package/dist/generated/public-contract.d.ts.map +1 -1
  24. package/dist/index.js +29 -27
  25. package/dist/index.js.map +1 -1
  26. package/dist/loader/auto-loader.d.ts.map +1 -1
  27. package/dist/manifest.json +37 -28
  28. package/dist/session/session.d.ts +36 -3
  29. package/dist/session/session.d.ts.map +1 -1
  30. package/dist/testing.js +1 -1
  31. package/dist/tip/index.d.ts +2 -0
  32. package/dist/tip/index.d.ts.map +1 -1
  33. package/dist/tip/mount.d.ts.map +1 -1
  34. package/dist/tip.js +211 -194
  35. package/dist/tip.js.map +1 -1
  36. package/dist/transport/transport.d.ts +2 -0
  37. package/dist/transport/transport.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/viceme.min.js +51 -8
  40. package/dist/viceme.min.js.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/chunks/client-DEg6YouY.js +0 -1027
  43. package/dist/chunks/client-DEg6YouY.js.map +0 -1
  44. package/dist/chunks/version-BJiUVcir.js +0 -6
@@ -0,0 +1,1471 @@
1
+ import { a as F, V as b, c as C, i as oe } from "./errors-C7DfLKcF.js";
2
+ import { a as Q, B as ne } from "./build-endpoints-NrDmg6jf.js";
3
+ import { S as se, A as ce } from "./version-DXLLix7K.js";
4
+ const le = /* @__PURE__ */ new Set(["cn", "global"]), de = {
5
+ cn: Q.cn,
6
+ global: Q.global
7
+ };
8
+ function Le(e) {
9
+ return de[e];
10
+ }
11
+ function ue(e) {
12
+ return typeof e == "string" && /^wrk_(?:test|live)_[A-Za-z0-9_-]{4,119}$/.test(e);
13
+ }
14
+ function fe(e) {
15
+ return typeof e == "string" && le.has(e);
16
+ }
17
+ function Re(e) {
18
+ if (typeof e != "object" || e === null)
19
+ throw F("createViceMe expects a configuration object.");
20
+ const t = e, r = /* @__PURE__ */ new Set(["workKey", "region", "signal"]);
21
+ for (const i of Object.keys(t))
22
+ if (!r.has(i))
23
+ throw F(`Unknown configuration field "${i}".`);
24
+ if (!ue(t.workKey))
25
+ throw F(
26
+ 'Configuration field "workKey" must start with "wrk_test_" or "wrk_live_".'
27
+ );
28
+ if (!fe(t.region))
29
+ throw F('Configuration field "region" must be "cn" or "global".');
30
+ if (t.signal !== void 0 && !(t.signal instanceof AbortSignal))
31
+ throw F('Configuration field "signal" must be an AbortSignal.');
32
+ return {
33
+ workKey: t.workKey,
34
+ region: t.region,
35
+ signal: t.signal
36
+ };
37
+ }
38
+ const he = {
39
+ CREATED: ["READY", "DESTROYED"],
40
+ READY: ["DEGRADED", "DESTROYED"],
41
+ DEGRADED: ["DESTROYED"],
42
+ DESTROYED: []
43
+ };
44
+ class me {
45
+ #e = "CREATED";
46
+ #r = /* @__PURE__ */ new Set();
47
+ get state() {
48
+ return this.#e;
49
+ }
50
+ get destroyed() {
51
+ return this.#e === "DESTROYED";
52
+ }
53
+ transition(t) {
54
+ if (t !== this.#e) {
55
+ if (!he[this.#e].includes(t))
56
+ throw new b({
57
+ code: "INTERNAL_ERROR",
58
+ message: `Illegal lifecycle transition ${this.#e} -> ${t}.`,
59
+ retryable: !1
60
+ });
61
+ this.#e = t;
62
+ for (const r of this.#r) r(t);
63
+ }
64
+ }
65
+ /** Any operation on a destroyed client must fail closed with this guard. */
66
+ assertAlive() {
67
+ if (this.destroyed) throw C();
68
+ }
69
+ subscribe(t) {
70
+ return this.#r.add(t), () => {
71
+ this.#r.delete(t);
72
+ };
73
+ }
74
+ clearListeners() {
75
+ this.#r.clear();
76
+ }
77
+ }
78
+ function ye(e, t, r) {
79
+ if (typeof e != "object" || e === null)
80
+ throw O();
81
+ const i = e;
82
+ if (typeof i.workKey != "string" || !Array.isArray(i.capabilities) || !i.capabilities.every((u) => typeof u == "string"))
83
+ throw O();
84
+ if (i.workKey !== t)
85
+ throw new b({
86
+ code: "WORK_NOT_FOUND",
87
+ message: "Work-session response did not match the requested work key.",
88
+ retryable: !1
89
+ });
90
+ const s = {
91
+ work: {
92
+ key: i.workKey,
93
+ capabilities: i.capabilities
94
+ }
95
+ };
96
+ if (i.accessProtocolVersion !== void 0) {
97
+ if (i.accessProtocolVersion !== 3) throw O();
98
+ const u = W(i.marketCapabilities);
99
+ if (r !== void 0 && u.market !== (r === "cn" ? "CN" : "GLOBAL") || !["CN", "GLOBAL"].includes(u.market) || !Array.isArray(u.loginMethods) || !u.loginMethods.every((d) => typeof d == "string") || !Array.isArray(u.supportedPriceCurrencies) || !u.supportedPriceCurrencies.every(
100
+ (d) => d === "CNY" || d === "USD"
101
+ ) || !["AVAILABLE", "PENDING_CHANNEL", "DISABLED"].includes(
102
+ u.checkoutAvailability
103
+ ) || typeof u.anonymousPurchase != "boolean")
104
+ throw O();
105
+ s.accessProtocolVersion = 3, s.marketCapabilities = u;
106
+ }
107
+ if (i.creator !== void 0 || i.work !== void 0) {
108
+ const u = W(i.creator), d = W(i.work);
109
+ if (typeof u.displayName != "string" || u.displayName.length === 0 || !X(u.avatarUrl) || !Number.isInteger(u.publishedWorkCount) || u.publishedWorkCount < 0 || typeof d.title != "string" || d.title.length === 0 || typeof d.summary != "string" || !X(d.coverUrl))
110
+ throw O();
111
+ s.work.creator = {
112
+ displayName: u.displayName,
113
+ avatarUrl: u.avatarUrl,
114
+ publishedWorkCount: u.publishedWorkCount
115
+ }, s.work.details = {
116
+ title: d.title,
117
+ summary: d.summary,
118
+ coverUrl: d.coverUrl
119
+ };
120
+ }
121
+ if (typeof i.token == "string" && (s.token = i.token), typeof i.expiresAt == "string") {
122
+ const u = new Date(i.expiresAt).getTime();
123
+ Number.isNaN(u) || (s.expiresAt = u);
124
+ }
125
+ return s;
126
+ }
127
+ function W(e) {
128
+ if (typeof e != "object" || e === null) throw O();
129
+ return e;
130
+ }
131
+ function X(e) {
132
+ if (e === null) return !0;
133
+ if (typeof e != "string") return !1;
134
+ try {
135
+ return new URL(e), !0;
136
+ } catch {
137
+ return !1;
138
+ }
139
+ }
140
+ function O() {
141
+ return new b({
142
+ code: "INTERNAL_ERROR",
143
+ message: "Malformed work-session response.",
144
+ retryable: !0
145
+ });
146
+ }
147
+ function B() {
148
+ return new b({
149
+ code: "SESSION_EXPIRED",
150
+ message: "The work session was invalidated before it completed.",
151
+ retryable: !0
152
+ });
153
+ }
154
+ class pe {
155
+ #e;
156
+ #r;
157
+ #t;
158
+ #a;
159
+ #i = 0;
160
+ #o = 0;
161
+ #n = !1;
162
+ constructor(t) {
163
+ this.#e = t, this.#r = t.now ?? (() => Date.now());
164
+ }
165
+ get snapshot() {
166
+ return this.#t;
167
+ }
168
+ /** Identity generation prevents a late bridge from undoing logout or account changes. */
169
+ get identityGeneration() {
170
+ return this.#o;
171
+ }
172
+ /** True when the cached snapshot's server-provided expiry has passed. */
173
+ #d() {
174
+ const t = this.#t?.expiresAt;
175
+ return t !== void 0 && t <= this.#r();
176
+ }
177
+ /**
178
+ * Establish (or return the established) public session.
179
+ *
180
+ * A cached snapshot is reused only while it is unexpired; an expired
181
+ * snapshot is dropped and re-authenticated. Concurrent callers share one
182
+ * in-flight request (single flight).
183
+ */
184
+ establish() {
185
+ if (this.#n) return Promise.reject(C());
186
+ if (this.#t) {
187
+ if (!this.#d())
188
+ return this.#t.userExpiresAt !== void 0 && this.#t.userExpiresAt <= this.#r() && (this.#i += 1, this.#o += 1, this.#t = {
189
+ ...this.#t,
190
+ user: void 0,
191
+ userToken: void 0,
192
+ userExpiresAt: void 0
193
+ }), this.#t.buyerExpiresAt !== void 0 && this.#t.buyerExpiresAt <= this.#r() && (this.#i += 1, this.#o += 1, this.#t = { ...this.#t, buyerToken: void 0, buyerExpiresAt: void 0 }), Promise.resolve(this.#t);
194
+ this.#i += 1, this.#t = void 0;
195
+ }
196
+ if (this.#a) return this.#a;
197
+ const t = this.#i, r = this.#e.transport.request({
198
+ method: "POST",
199
+ path: "/v1/public/work-sdk/sessions",
200
+ body: {
201
+ workKey: this.#e.workKey,
202
+ supportedAccessProtocolVersions: [3]
203
+ },
204
+ signal: this.#e.signal,
205
+ timeoutMs: this.#e.timeoutMs
206
+ }).then((i) => {
207
+ this.#c(t);
208
+ const s = ye(
209
+ i.body,
210
+ this.#e.workKey,
211
+ this.#e.region
212
+ );
213
+ return this.#c(t), this.#t = s, s;
214
+ }).finally(() => {
215
+ this.#a === r && (this.#a = void 0);
216
+ });
217
+ return this.#a = r, r;
218
+ }
219
+ async request(t) {
220
+ const r = await this.establish();
221
+ if (!r.token) throw O();
222
+ try {
223
+ return await this.#l(t, r);
224
+ } catch (i) {
225
+ if (this.#n) throw C();
226
+ if (t.signal?.aborted || this.#e.signal?.aborted || !(i instanceof b) || i.code !== "SESSION_EXPIRED") throw i;
227
+ this.#t === r && this.invalidate();
228
+ const s = await this.establish();
229
+ if (!s.token) throw O();
230
+ return this.#l(t, s);
231
+ }
232
+ }
233
+ authenticate(t) {
234
+ if (this.#s(), !this.#t) throw O();
235
+ if (t.expiresAt !== void 0 && t.expiresAt <= this.#r()) throw B();
236
+ this.#i += 1, this.#o += 1, this.#t = {
237
+ ...this.#t,
238
+ userToken: t.userToken,
239
+ user: t.user,
240
+ userExpiresAt: t.expiresAt,
241
+ buyerToken: void 0,
242
+ buyerExpiresAt: void 0
243
+ };
244
+ }
245
+ identifyBuyer(t, r) {
246
+ if (this.#s(), r !== this.#o || !this.#t || t.expiresAt <= this.#r()) throw B();
247
+ this.#i += 1, this.#o += 1, this.#t = {
248
+ ...this.#t,
249
+ user: void 0,
250
+ userToken: void 0,
251
+ userExpiresAt: void 0,
252
+ buyerToken: t.buyerToken,
253
+ buyerExpiresAt: t.expiresAt
254
+ };
255
+ }
256
+ async signOut() {
257
+ this.#s(), this.#o += 1, this.invalidate(), await this.establish();
258
+ }
259
+ /** Drop the token; next `establish()` re-authenticates. */
260
+ invalidate() {
261
+ this.#i += 1, this.#t = void 0, this.#a = void 0;
262
+ }
263
+ /** Hard cleanup: forget the token and pending work. */
264
+ destroy() {
265
+ this.#n || (this.#n = !0, this.#i += 1, this.#o += 1, this.#t = void 0, this.#a = void 0);
266
+ }
267
+ #s() {
268
+ if (this.#n) throw C();
269
+ }
270
+ #c(t) {
271
+ if (this.#s(), t !== this.#i) throw B();
272
+ }
273
+ async #l(t, r) {
274
+ this.#s();
275
+ const i = this.#i;
276
+ try {
277
+ const s = await this.#e.transport.request({
278
+ ...t,
279
+ authorization: r.token,
280
+ userAuthorization: r.userToken,
281
+ buyerAuthorization: r.buyerExpiresAt !== void 0 && r.buyerExpiresAt > this.#r() ? r.buyerToken : void 0,
282
+ signal: t.signal && this.#e.signal ? AbortSignal.any([t.signal, this.#e.signal]) : t.signal ?? this.#e.signal
283
+ });
284
+ return this.#s(), (t.method === "GET" || t.path === "/v1/public/work-sdk/access/check") && this.#c(i), s;
285
+ } catch (s) {
286
+ throw this.#n ? C() : s;
287
+ }
288
+ }
289
+ }
290
+ const z = "viceme-access-layer", H = 50;
291
+ function E() {
292
+ return typeof document < "u" && document.documentElement.lang.toLowerCase().startsWith("en");
293
+ }
294
+ function we(e) {
295
+ switch (e) {
296
+ case "SIGN_IN":
297
+ return {
298
+ description: "",
299
+ label: E() ? "Sign in" : "授权"
300
+ };
301
+ case "FOLLOW":
302
+ return {
303
+ description: "",
304
+ label: E() ? "Follow" : "关注"
305
+ };
306
+ case "CHECKOUT":
307
+ return {
308
+ description: "",
309
+ label: E() ? "Open checkout" : "打开支付"
310
+ };
311
+ case "RESOLVE_BUYER":
312
+ return {
313
+ description: "",
314
+ label: E() ? "Continue or restore purchase" : "继续购买或恢复权益"
315
+ };
316
+ }
317
+ }
318
+ function Z(e) {
319
+ const t = E() ? "Unable to complete this action. Please try again." : "操作未完成,请重试。";
320
+ if (!oe(e)) return t;
321
+ switch (e.code) {
322
+ case "CONFIG_INVALID":
323
+ return E() ? "This action is not configured correctly. Please try again later." : "操作配置无效,请稍后重试。";
324
+ case "AUTH_CANCELLED":
325
+ return E() ? "This action was cancelled. Please try again." : "操作已取消,请重试。";
326
+ case "SESSION_EXPIRED":
327
+ return E() ? "Your session expired. Please try again." : "授权会话已过期,请重试。";
328
+ case "NETWORK_TIMEOUT":
329
+ return E() ? "The connection timed out. Please try again." : "网络连接超时,请重试。";
330
+ default:
331
+ return e.requestId ? `${t} ${E() ? "Request ID:" : "请求 ID:"} ${e.requestId}` : t;
332
+ }
333
+ }
334
+ function ge() {
335
+ if (customElements.get(z)) return;
336
+ class e extends HTMLElement {
337
+ interaction;
338
+ connectedCallback() {
339
+ const r = we(this.interaction.action), i = this.attachShadow({ mode: "open" });
340
+ i.innerHTML = `
341
+ <style>
342
+ :host {
343
+ position: fixed;
344
+ inset: 0;
345
+ z-index: 2147483000;
346
+ display: grid;
347
+ align-items: end;
348
+ color: #18181b;
349
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
350
+ font-size: 16px;
351
+ line-height: 1.5;
352
+ }
353
+ [data-viceme='backdrop'] {
354
+ position: absolute;
355
+ inset: 0;
356
+ border: 0;
357
+ border-radius: 0;
358
+ background: transparent;
359
+ }
360
+ [data-viceme='panel'] {
361
+ position: relative;
362
+ box-sizing: border-box;
363
+ display: flex;
364
+ width: 100%;
365
+ max-height: min(92dvh, 46rem);
366
+ flex-direction: column;
367
+ overflow: auto;
368
+ border-radius: 1.25rem 1.25rem 0 0;
369
+ background: #ffffff;
370
+ color: #18181b;
371
+ padding: 3.75rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom));
372
+ box-shadow: 0 -1rem 3rem rgb(0 0 0 / 18%);
373
+ }
374
+ [data-viceme='content'] { display: flex; min-height: 0; flex-direction: column; }
375
+ [data-viceme='close'] {
376
+ position: absolute;
377
+ top: 0.75rem;
378
+ left: 0.75rem;
379
+ width: 2.75rem;
380
+ height: 2.75rem;
381
+ border: 0;
382
+ border-radius: 999px;
383
+ padding: 0;
384
+ background: transparent;
385
+ color: #52525b;
386
+ font-size: 2rem;
387
+ font-weight: 400;
388
+ line-height: 1;
389
+ }
390
+ [data-viceme='description'] { margin: 0.75rem 0 1.25rem; color: #71717a; line-height: 1.6; }
391
+ [data-viceme='profile'] {
392
+ display: none;
393
+ margin: 0;
394
+ border: 1px solid #e4e4e7;
395
+ border-radius: 1rem;
396
+ padding: 1.5rem;
397
+ background: #ffffff;
398
+ box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 6%);
399
+ text-align: center;
400
+ }
401
+ [data-viceme='profile'][data-visible='true'] { display: block; }
402
+ [data-viceme='avatar'] {
403
+ display: block;
404
+ width: 5.5rem;
405
+ height: 5.5rem;
406
+ margin: 0 auto 1rem;
407
+ border-radius: 999px;
408
+ object-fit: cover;
409
+ background: #f4f4f5;
410
+ }
411
+ [data-viceme='avatar-fallback'] {
412
+ display: grid;
413
+ width: 5.5rem;
414
+ height: 5.5rem;
415
+ margin: 0 auto 1rem;
416
+ place-items: center;
417
+ border-radius: 999px;
418
+ background: #f4f4f5;
419
+ color: #18181b;
420
+ font-size: 2rem;
421
+ font-weight: 700;
422
+ }
423
+ [data-viceme='avatar'][hidden], [data-viceme='avatar-fallback'][hidden] { display: none; }
424
+ [data-viceme='profile-summary'] {
425
+ display: flex;
426
+ min-width: 0;
427
+ align-items: baseline;
428
+ justify-content: center;
429
+ gap: 0.5rem;
430
+ }
431
+ [data-viceme='profile-name'] { margin: 0; font-size: 1.375rem; font-weight: 700; }
432
+ [data-viceme='profile-separator'], [data-viceme='profile-stats'] {
433
+ color: #71717a;
434
+ }
435
+ [data-viceme='profile-description'] {
436
+ margin: 0.25rem 0 0;
437
+ overflow-wrap: anywhere;
438
+ color: #71717a;
439
+ }
440
+ [data-viceme='profile-description']:empty { display: none; }
441
+ [data-viceme='profile-stats'] {
442
+ margin: 0;
443
+ font-size: 0.875rem;
444
+ }
445
+ [data-viceme='profile-header'] { min-width: 0; }
446
+ [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='description'] { display: none; }
447
+ [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile'][data-visible='true'] {
448
+ display: block;
449
+ border: 0;
450
+ padding: 0;
451
+ background: transparent;
452
+ box-shadow: none;
453
+ text-align: center;
454
+ }
455
+ [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile-name'] {
456
+ font-size: 1.125rem;
457
+ }
458
+ [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile-description'] {
459
+ display: none;
460
+ }
461
+ [data-viceme='work'] {
462
+ display: none;
463
+ overflow: hidden;
464
+ margin-top: 1.25rem;
465
+ border: 1px solid #e4e4e7;
466
+ border-radius: 1rem;
467
+ background: #fafafa;
468
+ text-align: left;
469
+ }
470
+ [data-viceme='work'][data-visible='true'] { display: block; }
471
+ [data-viceme='work-cover'] {
472
+ display: block;
473
+ width: 100%;
474
+ aspect-ratio: 16 / 9;
475
+ object-fit: cover;
476
+ background: #f4f4f5;
477
+ }
478
+ [data-viceme='work-cover'][hidden] { display: none; }
479
+ [data-viceme='work-copy'] { padding: 1rem; }
480
+ [data-viceme='work-title'] {
481
+ margin: 0;
482
+ color: #18181b;
483
+ font-size: 1rem;
484
+ font-weight: 700;
485
+ line-height: 1.5;
486
+ }
487
+ [data-viceme='work-summary'] {
488
+ display: -webkit-box;
489
+ overflow: hidden;
490
+ margin: 0.375rem 0 0;
491
+ color: #71717a;
492
+ font-size: 0.875rem;
493
+ line-height: 1.5;
494
+ -webkit-box-orient: vertical;
495
+ -webkit-line-clamp: 2;
496
+ }
497
+ [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='action'] {
498
+ width: 100%;
499
+ }
500
+ [data-viceme='actions'] {
501
+ display: flex;
502
+ justify-content: flex-end;
503
+ gap: 0.75rem;
504
+ margin-top: 1.25rem;
505
+ }
506
+ button {
507
+ box-sizing: border-box;
508
+ display: inline-flex;
509
+ height: 3.25rem;
510
+ align-items: center;
511
+ justify-content: center;
512
+ border-radius: 0.75rem;
513
+ padding: 0.625rem 1rem;
514
+ font: 600 1rem/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
515
+ cursor: pointer;
516
+ }
517
+ button:focus-visible, iframe:focus-visible { outline: 2px solid #18181b; outline-offset: 2px; }
518
+ [data-viceme='action'] {
519
+ width: min(11rem, 48%);
520
+ border: 1px solid #18181b;
521
+ background: #18181b;
522
+ color: #ffffff;
523
+ }
524
+ [data-viceme='action']:hover { background: #3f3f46; border-color: #3f3f46; }
525
+ [data-viceme='actions'][data-single='true'] [data-viceme='action'] { width: 100%; }
526
+ button:disabled { cursor: wait; opacity: 0.5; }
527
+ button[hidden] { display: none; }
528
+ [data-viceme='error'] { margin: 0.75rem 0 0; color: #b91c1c; font-size: 0.875rem; }
529
+ [data-viceme='error']:empty { display: none; }
530
+ [data-viceme='frame'] {
531
+ display: none;
532
+ width: 100%;
533
+ min-height: 0;
534
+ flex: 1 1 auto;
535
+ border: 0;
536
+ border-radius: 0.75rem;
537
+ background: #ffffff;
538
+ }
539
+ [data-viceme='panel'][data-frame='true'] {
540
+ height: min(92dvh, 46rem);
541
+ max-height: 92dvh;
542
+ overflow: hidden;
543
+ }
544
+ [data-viceme='panel'][data-frame='true'] [data-viceme='content'] { display: none; }
545
+ [data-viceme='panel'][data-frame='true'] [data-viceme='frame'] { display: block; }
546
+ @media (min-width: 48rem) {
547
+ :host { place-items: center; padding: 1.5rem; }
548
+ [data-viceme='panel'] {
549
+ width: min(24rem, 100%);
550
+ border-radius: 1.25rem;
551
+ padding: 3.75rem 1.25rem 1.25rem;
552
+ box-shadow: 0 1.5rem 4rem rgb(0 0 0 / 24%);
553
+ }
554
+ [data-viceme='panel'][data-frame='true'] { width: min(30rem, 100%); }
555
+ [data-viceme='panel'][data-action='SIGN_IN'] { width: min(30rem, 100%); }
556
+ [data-viceme='panel'][data-action='CHECKOUT'][data-frame='true'] {
557
+ width: min(42rem, 100%);
558
+ }
559
+ }
560
+ @media (prefers-reduced-motion: no-preference) {
561
+ [data-viceme='panel'] { animation: viceme-enter 160ms ease-out; }
562
+ @keyframes viceme-enter { from { opacity: 0; transform: translateY(1rem); } }
563
+ }
564
+ </style>
565
+ <button data-viceme="backdrop" type="button" tabindex="-1" aria-label="${E() ? "Close" : "关闭"}"></button>
566
+ <section data-viceme="panel" role="dialog" aria-modal="true" aria-label="${E() ? "ViceMe access" : "ViceMe 授权"}">
567
+ <button data-viceme="close" type="button" aria-label="${E() ? "Close" : "关闭"}">×</button>
568
+ <div data-viceme="content">
569
+ <p data-viceme="description"></p>
570
+ <section data-viceme="profile" aria-label="${E() ? "Creator" : "创作者"}">
571
+ <div data-viceme="profile-header">
572
+ <img data-viceme="avatar" hidden />
573
+ <span data-viceme="avatar-fallback" aria-hidden="true"></span>
574
+ <div data-viceme="profile-summary">
575
+ <p data-viceme="profile-name"></p>
576
+ <span data-viceme="profile-separator" aria-hidden="true">·</span>
577
+ <p data-viceme="profile-stats"></p>
578
+ </div>
579
+ </div>
580
+ <p data-viceme="profile-description"></p>
581
+ </section>
582
+ <article data-viceme="work">
583
+ <img data-viceme="work-cover" hidden />
584
+ <div data-viceme="work-copy">
585
+ <p data-viceme="work-title"></p>
586
+ <p data-viceme="work-summary"></p>
587
+ </div>
588
+ </article>
589
+ <p data-viceme="error" role="alert" aria-live="polite"></p>
590
+ <div data-viceme="actions">
591
+ <button data-viceme="action" type="button"></button>
592
+ </div>
593
+ </div>
594
+ <iframe data-viceme="frame" title="" referrerpolicy="no-referrer" allow="payment"></iframe>
595
+ <button data-viceme="continue" type="button" hidden>${E() ? "Continue in this page" : "在当前页面继续"}</button>
596
+ </section>
597
+ `;
598
+ const s = i.querySelector("[data-viceme='panel']");
599
+ s.dataset.action = this.interaction.action, s.dataset.frame = "false";
600
+ const u = i.querySelector("[data-viceme='description']");
601
+ u.textContent = r.description;
602
+ const d = i.querySelector("[data-viceme='action']"), I = d.parentElement, w = i.querySelector("[data-viceme='close']"), U = i.querySelector("[data-viceme='backdrop']"), D = i.querySelector("[data-viceme='error']"), v = i.querySelector("[data-viceme='frame']"), g = i.querySelector("[data-viceme='continue']"), M = i.querySelector("[data-viceme='profile']"), _ = i.querySelector("[data-viceme='avatar']"), R = i.querySelector("[data-viceme='avatar-fallback']"), P = i.querySelector("[data-viceme='profile-name']"), G = i.querySelector(
603
+ "[data-viceme='profile-description']"
604
+ ), o = i.querySelector("[data-viceme='profile-stats']"), c = i.querySelector("[data-viceme='work']"), n = i.querySelector("[data-viceme='work-cover']"), a = i.querySelector("[data-viceme='work-title']"), l = i.querySelector("[data-viceme='work-summary']");
605
+ d.textContent = r.label, d.hidden = !1, I.dataset.single = "true";
606
+ const m = r.label;
607
+ v.title = this.interaction.action === "SIGN_IN" ? "登录授权" : this.interaction.action === "RESOLVE_BUYER" ? "购买权益恢复" : "支付";
608
+ const h = this.interaction.followTarget;
609
+ if (h) {
610
+ s.setAttribute(
611
+ "aria-label",
612
+ this.interaction.action === "SIGN_IN" ? `授权 ${h.displayName}` : `关注 ${h.displayName}`
613
+ ), M.dataset.visible = "true", P.textContent = h.displayName;
614
+ const f = [...h.description ?? ""];
615
+ G.textContent = f.length > H ? `${f.slice(0, H).join("")}…` : f.join(""), f.length > H && (G.title = h.description), o.textContent = `${h.workCount} 个作品`, R.textContent = h.displayName.trim().slice(0, 1) || "V", h.avatarUrl && (_.src = h.avatarUrl, _.alt = `${h.displayName}的头像`, _.hidden = !1, R.hidden = !0);
616
+ }
617
+ const y = this.interaction.work;
618
+ y && (c.dataset.visible = "true", a.textContent = y.title, l.textContent = y.summary, y.coverUrl && (n.src = y.coverUrl, n.alt = y.title, n.hidden = !1));
619
+ let k = null, N = !1;
620
+ const V = (f) => {
621
+ N || (N = !0, this.interaction.signal?.removeEventListener("abort", T), this.dispatchEvent(new CustomEvent("viceme:access-layer-close", { detail: f })));
622
+ }, T = () => {
623
+ k?.cancel(), V("dismissed");
624
+ };
625
+ this.interaction.signal?.addEventListener("abort", T, { once: !0 }), this.interaction.signal?.aborted && queueMicrotask(T), U.addEventListener("click", T), w.addEventListener("click", T), g.addEventListener("click", () => {
626
+ try {
627
+ k?.type === "frame" && k.continueInSamePage?.();
628
+ } catch (f) {
629
+ D.textContent = Z(f), s.dataset.frame = "false";
630
+ }
631
+ }), this.addEventListener("keydown", (f) => {
632
+ if (f.key === "Escape" && T(), f.key === "Tab") {
633
+ if (f.preventDefault(), k?.type === "frame") {
634
+ const K = [
635
+ w,
636
+ v,
637
+ ...g.hidden ? [] : [g]
638
+ ], ae = K.indexOf(i.activeElement);
639
+ K[(ae + (f.shiftKey ? -1 : 1) + K.length) % K.length]?.focus();
640
+ return;
641
+ }
642
+ const A = [w, ...d.hidden ? [] : [d]].filter((K) => !K.disabled && !K.hidden);
643
+ if (A.length === 0) return;
644
+ const $ = A.indexOf(i.activeElement), ie = f.shiftKey ? -1 : 1;
645
+ A[($ + ie + A.length) % A.length]?.focus();
646
+ }
647
+ });
648
+ const S = async () => {
649
+ d.disabled = !0, d.setAttribute("aria-busy", "true"), d.textContent = E() ? "Opening…" : "正在打开…", D.textContent = "";
650
+ try {
651
+ const f = await this.interaction.perform();
652
+ if (N || this.interaction.signal?.aborted) {
653
+ f.type !== "completed" && f.cancel();
654
+ return;
655
+ }
656
+ f.type === "frame" ? (k = f, g.hidden = !f.continueInSamePage, s.dataset.frame = "true", v.src = f.url, v.focus(), await f.completion) : f.type === "external" && (k = f, await f.completion), V("acted");
657
+ } catch (f) {
658
+ if (N) return;
659
+ k?.cancel(), k = null, g.hidden = !0, s.dataset.frame = "false", v.removeAttribute("src"), D.textContent = Z(f), d.hidden = !1, d.disabled = !1, d.removeAttribute("aria-busy"), d.textContent = m, d.focus();
660
+ }
661
+ };
662
+ d.addEventListener("click", S), queueMicrotask(() => {
663
+ N || (this.interaction.autoStart ? S() : d.focus());
664
+ });
665
+ }
666
+ }
667
+ customElements.define(z, e);
668
+ }
669
+ const be = async (e) => {
670
+ if (typeof document > "u" || typeof customElements > "u" || e.signal?.aborted) return "dismissed";
671
+ ge();
672
+ const t = document.createElement(z);
673
+ t.interaction = e;
674
+ const r = document.documentElement.style.overflow, i = document.activeElement instanceof HTMLElement ? document.activeElement : null;
675
+ document.documentElement.style.overflow = "hidden", document.body.append(t);
676
+ try {
677
+ return await new Promise((s) => {
678
+ t.addEventListener(
679
+ "viceme:access-layer-close",
680
+ (u) => s(u.detail),
681
+ { once: !0 }
682
+ );
683
+ });
684
+ } finally {
685
+ t.remove(), document.documentElement.style.overflow = r, i?.focus();
686
+ }
687
+ };
688
+ function x() {
689
+ return new b({
690
+ code: "INTERNAL_ERROR",
691
+ message: "Malformed access bridge response.",
692
+ retryable: !1
693
+ });
694
+ }
695
+ function J(e) {
696
+ if (typeof e != "object" || e === null || Array.isArray(e)) throw x();
697
+ return e;
698
+ }
699
+ function j(e) {
700
+ return btoa(String.fromCharCode(...e)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
701
+ }
702
+ function ee(e, t) {
703
+ if (typeof e != "string") throw x();
704
+ let r;
705
+ try {
706
+ r = new URL(e);
707
+ } catch {
708
+ throw x();
709
+ }
710
+ if (r.protocol !== "https:" || r.origin !== t || r.username || r.password)
711
+ throw x();
712
+ return r.href;
713
+ }
714
+ function Y() {
715
+ return new b({
716
+ code: "SESSION_EXPIRED",
717
+ message: "Access recovery expired. Please try again.",
718
+ retryable: !0
719
+ });
720
+ }
721
+ function ve(e) {
722
+ const t = `viceme:access-bridge:v3:${e.widgetOrigin}:${e.workKey}`;
723
+ let r;
724
+ const i = () => {
725
+ r?.abort(e.signal.aborted ? e.signal.reason : void 0), r = void 0;
726
+ try {
727
+ sessionStorage.removeItem(t);
728
+ } catch {
729
+ }
730
+ };
731
+ return e.signal.addEventListener("abort", i, { once: !0 }), {
732
+ clear: i,
733
+ async start(s, u) {
734
+ if (e.signal.aborted) throw e.signal.reason ?? C();
735
+ if (r)
736
+ throw new b({
737
+ code: "CONFIG_INVALID",
738
+ message: "An access interaction is already open.",
739
+ retryable: !0
740
+ });
741
+ if (typeof window > "u" || !globalThis.crypto?.subtle)
742
+ throw new b({
743
+ code: "CONFIG_INVALID",
744
+ message: "Access recovery requires a browser with Web Crypto.",
745
+ retryable: !1
746
+ });
747
+ const d = new AbortController();
748
+ r = d;
749
+ const I = AbortSignal.any([e.signal, d.signal]), w = () => {
750
+ if (I.aborted) throw I.reason ?? C();
751
+ };
752
+ try {
753
+ await e.session.establish();
754
+ const U = e.session.identityGeneration, D = async (n, a) => {
755
+ w();
756
+ const l = await e.session.establish(), m = await e.session.request({
757
+ method: "POST",
758
+ path: n,
759
+ signal: I,
760
+ body: { ...a, workSessionToken: l.token }
761
+ });
762
+ return w(), J(m.body);
763
+ };
764
+ let v;
765
+ try {
766
+ const n = JSON.parse(sessionStorage.getItem(t) ?? "null");
767
+ n && (n.purpose === s || s === "IDENTIFY" && ["RESTORE", "CLAIM"].includes(n.purpose)) && n.featureKey === u && typeof n.expiresAt == "number" && n.expiresAt > e.now() && n.expiresAt <= e.now() + 3e5 && typeof n.challengeId == "string" && /^[A-Za-z0-9_-]+$/.test(n.challengeId) && typeof n.verifier == "string" && /^[A-Za-z0-9_-]{43,128}$/.test(n.verifier) && typeof n.state == "string" && (v = {
768
+ ...n,
769
+ bridgeUrl: ee(n.bridgeUrl, e.widgetOrigin)
770
+ }, s = v.purpose);
771
+ } catch {
772
+ }
773
+ if (!v) {
774
+ const n = j(crypto.getRandomValues(new Uint8Array(32))), a = j(crypto.getRandomValues(new Uint8Array(32))), l = j(
775
+ new Uint8Array(
776
+ await crypto.subtle.digest("SHA-256", new TextEncoder().encode(n))
777
+ )
778
+ );
779
+ w();
780
+ const m = /^https?:$/.test(window.location.protocol) ? window.location.href : void 0, h = await D("/v1/public/work-sdk/buyer/challenges", {
781
+ purpose: s,
782
+ ...u ? { featureKey: u } : {},
783
+ codeChallenge: l,
784
+ state: a,
785
+ requestId: crypto.randomUUID(),
786
+ ...m ? { returnUrl: m } : {}
787
+ }), y = typeof h.expiresAt == "string" ? Date.parse(h.expiresAt) : NaN;
788
+ if (typeof h.challengeId != "string" || !/^[A-Za-z0-9_-]+$/.test(h.challengeId) || !Number.isFinite(y) || y <= e.now())
789
+ throw x();
790
+ v = {
791
+ challengeId: h.challengeId,
792
+ bridgeUrl: ee(h.bridgeUrl, e.widgetOrigin),
793
+ expiresAt: Math.min(y, e.now() + 3e5),
794
+ verifier: n,
795
+ state: a,
796
+ purpose: s,
797
+ featureKey: u
798
+ };
799
+ }
800
+ const g = v;
801
+ let M = !1;
802
+ const _ = () => {
803
+ if (r === d && (r = void 0), !M)
804
+ try {
805
+ sessionStorage.removeItem(t);
806
+ } catch {
807
+ }
808
+ };
809
+ let R, P;
810
+ const G = () => new Promise((n, a) => {
811
+ const l = () => {
812
+ R && clearTimeout(R), a(I.reason);
813
+ };
814
+ I.addEventListener("abort", l, { once: !0 }), R = setTimeout(() => {
815
+ I.removeEventListener("abort", l), n();
816
+ }, 1e3), I.aborted && l();
817
+ }), o = async () => {
818
+ P = setTimeout(
819
+ () => d.abort(Y()),
820
+ Math.max(0, g.expiresAt - e.now())
821
+ );
822
+ try {
823
+ for (; e.now() < g.expiresAt; ) {
824
+ w();
825
+ const n = await D(
826
+ `/v1/public/work-sdk/buyer/challenges/${g.challengeId}/result`,
827
+ { codeVerifier: g.verifier }
828
+ );
829
+ if (n.status === "EXPIRED") throw Y();
830
+ if (n.status === "PENDING") {
831
+ await G();
832
+ continue;
833
+ }
834
+ if (n.status !== "READY" || typeof n.code != "string" || !n.code)
835
+ throw x();
836
+ const a = await D("/v1/public/work-sdk/buyer/exchange", {
837
+ code: n.code,
838
+ codeVerifier: g.verifier
839
+ });
840
+ if (w(), e.session.identityGeneration !== U) throw Y();
841
+ if (a.purpose !== s) throw x();
842
+ const l = typeof a.expiresAt == "string" ? Date.parse(a.expiresAt) : NaN;
843
+ if (!Number.isFinite(l) || l <= e.now())
844
+ throw x();
845
+ if (typeof a.userToken == "string" && a.userToken) {
846
+ if (s !== "SIGN_IN" && s !== "CLAIM") throw x();
847
+ const m = J(a.user);
848
+ if (typeof m.id != "string" || !(typeof m.displayName == "string" || m.displayName === null) || !(typeof m.avatarUrl == "string" || m.avatarUrl === null))
849
+ throw x();
850
+ const h = {
851
+ subject: m.id,
852
+ nickname: m.displayName,
853
+ avatarUrl: m.avatarUrl
854
+ };
855
+ e.session.authenticate({
856
+ userToken: a.userToken,
857
+ user: h,
858
+ expiresAt: l
859
+ });
860
+ } else {
861
+ const m = typeof a.expiresAt == "string" ? Date.parse(a.expiresAt) : NaN;
862
+ if (s === "SIGN_IN" || s === "CLAIM" || typeof a.buyerToken != "string" || !a.buyerToken || !Number.isFinite(m))
863
+ throw x();
864
+ e.session.identifyBuyer(
865
+ { buyerToken: a.buyerToken, expiresAt: m },
866
+ U
867
+ );
868
+ }
869
+ return;
870
+ }
871
+ throw Y();
872
+ } finally {
873
+ P && clearTimeout(P), R && clearTimeout(R), _();
874
+ }
875
+ };
876
+ let c;
877
+ return {
878
+ type: "frame",
879
+ url: g.bridgeUrl,
880
+ get completion() {
881
+ return c ??= o();
882
+ },
883
+ cancel: () => {
884
+ d.abort(), _();
885
+ },
886
+ continueInSamePage: () => {
887
+ w();
888
+ try {
889
+ sessionStorage.setItem(t, JSON.stringify(g));
890
+ } catch {
891
+ throw new b({
892
+ code: "CONFIG_INVALID",
893
+ message: "Browser storage is unavailable. Use the recovery page in another window.",
894
+ retryable: !0
895
+ });
896
+ }
897
+ M = !0, d.abort(), window.location.assign(g.bridgeUrl);
898
+ }
899
+ };
900
+ } catch (U) {
901
+ throw r === d && (r = void 0), d.abort(), U;
902
+ }
903
+ }
904
+ };
905
+ }
906
+ function L(e) {
907
+ if (typeof e != "object" || e === null) throw p();
908
+ return e;
909
+ }
910
+ function p() {
911
+ return new b({
912
+ code: "INTERNAL_ERROR",
913
+ message: "Malformed public API response.",
914
+ retryable: !0
915
+ });
916
+ }
917
+ function Ee(e) {
918
+ const t = L(e);
919
+ if (typeof t.id != "string" || !(typeof t.displayName == "string" || t.displayName === null) || !(typeof t.avatarUrl == "string" || t.avatarUrl === null))
920
+ throw p();
921
+ return {
922
+ subject: t.id,
923
+ nickname: t.displayName,
924
+ avatarUrl: t.avatarUrl
925
+ };
926
+ }
927
+ function te(e) {
928
+ const t = L(e);
929
+ if (typeof t.following != "boolean" || !(typeof t.followedAt == "string" || t.followedAt === null))
930
+ throw p();
931
+ const r = L(t.creator);
932
+ if (typeof r.displayName != "string" || !(typeof r.avatarUrl == "string" || r.avatarUrl === null) || !(typeof r.description == "string" || r.description === null) || !Number.isInteger(r.publishedWorkCount) || r.publishedWorkCount < 0)
933
+ throw p();
934
+ return {
935
+ following: t.following,
936
+ followedAt: t.followedAt,
937
+ target: {
938
+ kind: "CREATOR",
939
+ displayName: r.displayName,
940
+ avatarUrl: r.avatarUrl,
941
+ description: r.description,
942
+ workCount: r.publishedWorkCount
943
+ }
944
+ };
945
+ }
946
+ function ke(e, t) {
947
+ const r = L(e), i = /* @__PURE__ */ new Set([
948
+ "PUBLIC",
949
+ "OWNER",
950
+ "FOLLOWING",
951
+ "ENTITLED",
952
+ "AUTH_REQUIRED",
953
+ "FOLLOW_REQUIRED",
954
+ "PURCHASE_REQUIRED",
955
+ "FEATURE_NOT_FOUND",
956
+ "FEATURE_DISABLED"
957
+ ]), s = /* @__PURE__ */ new Set([null, "SIGN_IN", "FOLLOW", "CHECKOUT"]);
958
+ if (t === 3 && (i.add("BUYER_REQUIRED").add("FEATURE_NOT_READY").add("PAYMENT_CHANNEL_UNAVAILABLE"), s.add("RESOLVE_BUYER")), typeof r.allowed != "boolean" || typeof r.reason != "string" || !i.has(r.reason) || !s.has(r.nextAction))
959
+ throw p();
960
+ return {
961
+ allowed: r.allowed,
962
+ reason: r.reason,
963
+ nextAction: r.nextAction
964
+ };
965
+ }
966
+ function Ae(e, t) {
967
+ const r = L(e);
968
+ if (typeof r.featureKey != "string" || !/^[a-z][a-z0-9_-]{1,63}$/.test(r.featureKey) || typeof r.title != "string" || r.title.trim().length === 0 || r.title.length > 120 || !(r.policyType === "PUBLIC" || r.policyType === "FOLLOW_OWNER" || r.policyType === "WORK_ENTITLEMENT"))
969
+ throw p();
970
+ const i = r.price === null ? null : L(r.price);
971
+ if (t === 3) {
972
+ const s = (I) => {
973
+ if (I === null) return null;
974
+ const w = L(I);
975
+ if (!Number.isSafeInteger(w.amountMinor) || w.amountMinor <= 0 || !(w.currency === "CNY" || w.currency === "USD"))
976
+ throw p();
977
+ return { amountMinor: w.amountMinor, currency: w.currency };
978
+ };
979
+ if (r.status !== "ACTIVE" && r.status !== "PENDING_CHANNEL" && r.status !== "DISABLED")
980
+ throw p();
981
+ const u = s(i), d = s(r.pricingIntent);
982
+ if (r.policyType !== "WORK_ENTITLEMENT" && (u !== null || r.status === "PENDING_CHANNEL") || r.policyType === "WORK_ENTITLEMENT" && r.status === "ACTIVE" && u === null || r.status === "PENDING_CHANNEL" && (u !== null || d === null))
983
+ throw p();
984
+ return {
985
+ featureKey: r.featureKey,
986
+ title: r.title,
987
+ policy: { type: r.policyType },
988
+ price: u,
989
+ status: r.status,
990
+ pricingIntent: d
991
+ };
992
+ }
993
+ if (i !== null && (!Number.isInteger(i.amountCents) || i.amountCents <= 0 || i.currency !== "CNY") || r.policyType === "WORK_ENTITLEMENT" != (i !== null))
994
+ throw p();
995
+ return {
996
+ featureKey: r.featureKey,
997
+ title: r.title,
998
+ policy: { type: r.policyType },
999
+ price: i === null ? null : { amountCents: i.amountCents, currency: "CNY" }
1000
+ };
1001
+ }
1002
+ function Ie() {
1003
+ const e = crypto.getRandomValues(new Uint8Array(32));
1004
+ return Ne(e);
1005
+ }
1006
+ function Ne(e) {
1007
+ let t = "";
1008
+ for (const r of e) t += String.fromCharCode(r);
1009
+ return btoa(t).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
1010
+ }
1011
+ function re() {
1012
+ return typeof document < "u" && document.documentElement.lang.toLowerCase() === "en-us" ? "en-US" : "zh-CN";
1013
+ }
1014
+ function Se(e) {
1015
+ const t = ve(e), r = () => new b({
1016
+ code: "AUTH_CANCELLED",
1017
+ message: "The interactive action was cancelled.",
1018
+ retryable: !1
1019
+ }), i = () => e.signal.reason instanceof Error ? e.signal.reason : C(), s = (o) => {
1020
+ if (e.signal.aborted) return Promise.reject(i());
1021
+ let c;
1022
+ const n = new Promise((l, m) => {
1023
+ c = () => m(i()), e.signal.addEventListener("abort", c, { once: !0 }), e.signal.aborted && c();
1024
+ });
1025
+ let a;
1026
+ try {
1027
+ a = (e.presenter ?? be)({
1028
+ ...o,
1029
+ signal: e.signal
1030
+ });
1031
+ } catch (l) {
1032
+ a = Promise.reject(l);
1033
+ }
1034
+ return Promise.race([a, n]).then((l) => {
1035
+ if (e.signal.aborted) throw i();
1036
+ return l;
1037
+ }).finally(() => {
1038
+ c && e.signal.removeEventListener("abort", c);
1039
+ });
1040
+ }, u = (o, c, n, a, l, m) => {
1041
+ if (typeof window > "u")
1042
+ throw new b({
1043
+ code: "CONFIG_INVALID",
1044
+ message: "Interactive access requires a browser window.",
1045
+ retryable: !1
1046
+ });
1047
+ let h = !0, y, k;
1048
+ const N = () => {
1049
+ h && (h = !1, window.removeEventListener("message", T));
1050
+ }, V = new Promise((S, f) => {
1051
+ y = S, k = f;
1052
+ }), T = (S) => {
1053
+ if (!h || S.origin !== c || typeof S.data != "object" || S.data === null) return;
1054
+ const f = S.data;
1055
+ if (!(f.workKey !== e.workKey || f.channel !== n)) {
1056
+ if (f.type === `viceme:${a}:ready`) {
1057
+ S.source && "postMessage" in S.source && S.source.postMessage(
1058
+ {
1059
+ type: `viceme:${a}:init`,
1060
+ workKey: e.workKey,
1061
+ channel: n,
1062
+ ...l
1063
+ },
1064
+ c
1065
+ );
1066
+ return;
1067
+ }
1068
+ if (f.type === `viceme:${a}:cancelled`) {
1069
+ N(), k(r());
1070
+ return;
1071
+ }
1072
+ f.type === `viceme:${a}:complete` && (N(), m(f).then(y, k));
1073
+ }
1074
+ };
1075
+ return window.addEventListener("message", T), {
1076
+ type: "frame",
1077
+ url: o,
1078
+ completion: V,
1079
+ cancel() {
1080
+ N(), y();
1081
+ }
1082
+ };
1083
+ }, d = async () => {
1084
+ if (await e.ready(), e.session.snapshot?.accessProtocolVersion === 3) return t.start("SIGN_IN");
1085
+ if (typeof window > "u")
1086
+ throw new b({
1087
+ code: "CONFIG_INVALID",
1088
+ message: "Interactive access requires a browser window.",
1089
+ retryable: !1
1090
+ });
1091
+ const o = Ie(), c = new URL("/sdk/login", e.widgetOrigin);
1092
+ c.search = new URLSearchParams({
1093
+ workKey: e.workKey,
1094
+ channel: o,
1095
+ parentOrigin: window.location.origin,
1096
+ locale: re()
1097
+ }).toString();
1098
+ const n = e.session.snapshot?.token;
1099
+ if (!n) throw p();
1100
+ return u(
1101
+ c.toString(),
1102
+ e.widgetOrigin,
1103
+ o,
1104
+ "auth",
1105
+ { workSessionToken: n },
1106
+ async (a) => {
1107
+ if (typeof a.userToken != "string")
1108
+ throw p();
1109
+ e.session.authenticate({ userToken: a.userToken, user: Ee(a.user) });
1110
+ }
1111
+ );
1112
+ }, I = async () => (await e.ready(), te(
1113
+ (await e.session.request({ method: "GET", path: "/v1/public/work-sdk/follow" })).body
1114
+ )), w = async () => (await e.ready(), te(
1115
+ (await e.session.request({ method: "PUT", path: "/v1/public/work-sdk/follow" })).body
1116
+ )), U = () => {
1117
+ const o = e.session.snapshot?.work;
1118
+ return {
1119
+ ...o?.creator ? {
1120
+ followTarget: {
1121
+ kind: "CREATOR",
1122
+ displayName: o.creator.displayName,
1123
+ avatarUrl: o.creator.avatarUrl,
1124
+ description: null,
1125
+ workCount: o.creator.publishedWorkCount
1126
+ }
1127
+ } : {},
1128
+ ...o?.details ? { work: o.details } : {}
1129
+ };
1130
+ }, D = {
1131
+ async getState() {
1132
+ await e.ready();
1133
+ const o = e.session.snapshot?.user ?? null;
1134
+ return { authenticated: o !== null, user: o };
1135
+ },
1136
+ async signIn() {
1137
+ if (await e.ready(), await s({
1138
+ featureKey: "auth",
1139
+ reason: "AUTH_REQUIRED",
1140
+ action: "SIGN_IN",
1141
+ autoStart: e.session.snapshot?.accessProtocolVersion === 3,
1142
+ ...U(),
1143
+ perform: d
1144
+ }) === "dismissed") throw r();
1145
+ return this.getState();
1146
+ },
1147
+ async signOut() {
1148
+ await e.ready(), t.clear(), await e.session.signOut();
1149
+ }
1150
+ }, v = {
1151
+ getState: I,
1152
+ follow: w,
1153
+ unfollow: async () => {
1154
+ throw new b({
1155
+ code: "CAPABILITY_DISABLED",
1156
+ message: "Unfollow is not exposed by website access.",
1157
+ retryable: !1
1158
+ });
1159
+ }
1160
+ }, g = async (o) => {
1161
+ await e.ready();
1162
+ const c = L(
1163
+ (await e.session.request({
1164
+ method: "POST",
1165
+ path: "/v1/public/work-sdk/access/check",
1166
+ body: { featureKeys: o }
1167
+ })).body
1168
+ ), n = L(c.decisions);
1169
+ return Object.fromEntries(
1170
+ Object.entries(n).map(([a, l]) => [
1171
+ a,
1172
+ ke(l, e.session.snapshot?.accessProtocolVersion)
1173
+ ])
1174
+ );
1175
+ }, M = async (o, c = {}) => {
1176
+ await e.ready();
1177
+ const n = {
1178
+ featureKey: o,
1179
+ locale: c.locale ?? (e.session.snapshot?.accessProtocolVersion === 3 ? re() : "zh-CN"),
1180
+ ...e.session.snapshot?.accessProtocolVersion === 3 && typeof window < "u" && /^https?:$/.test(window.location.protocol) ? { returnUrl: window.location.href } : {}
1181
+ }, a = L(
1182
+ (await e.session.request({
1183
+ method: "POST",
1184
+ path: "/v1/public/work-sdk/checkout",
1185
+ body: n
1186
+ })).body
1187
+ );
1188
+ if (typeof a.checkoutUrl != "string" || typeof a.alreadyOwned != "boolean" || !(a.expiresAt === null || typeof a.expiresAt == "string" && !Number.isNaN(Date.parse(a.expiresAt))) || a.alreadyOwned !== (a.expiresAt === null))
1189
+ throw p();
1190
+ let l;
1191
+ try {
1192
+ l = new URL(a.checkoutUrl);
1193
+ } catch {
1194
+ throw p();
1195
+ }
1196
+ if (!a.alreadyOwned && (l.protocol !== "https:" || l.origin !== e.widgetOrigin))
1197
+ throw p();
1198
+ return {
1199
+ checkoutUrl: a.checkoutUrl,
1200
+ alreadyOwned: a.alreadyOwned,
1201
+ expiresAt: a.expiresAt
1202
+ };
1203
+ }, _ = (o, c) => {
1204
+ if (o.alreadyOwned) return { type: "completed" };
1205
+ const n = Date.parse(o.expiresAt);
1206
+ if (typeof window > "u")
1207
+ throw new b({
1208
+ code: "CONFIG_INVALID",
1209
+ message: "Hosted checkout requires a browser window.",
1210
+ retryable: !1
1211
+ });
1212
+ let a = !0, l, m, h, y;
1213
+ const k = new Promise((A, $) => {
1214
+ h = A, y = $;
1215
+ }), N = () => {
1216
+ l && clearTimeout(l), m && clearTimeout(m), document.removeEventListener("visibilitychange", f);
1217
+ }, V = () => {
1218
+ a && (a = !1, N(), y(
1219
+ new b({
1220
+ code: "SESSION_EXPIRED",
1221
+ message: "Hosted checkout session expired.",
1222
+ retryable: !0
1223
+ })
1224
+ ));
1225
+ }, T = () => {
1226
+ if (!a || document.visibilityState === "hidden") return;
1227
+ const A = n - e.now();
1228
+ if (A <= 0) {
1229
+ V();
1230
+ return;
1231
+ }
1232
+ l = setTimeout(() => {
1233
+ S();
1234
+ }, Math.min(1500, A));
1235
+ }, S = async () => {
1236
+ if (a)
1237
+ try {
1238
+ const A = (await g([c]))[c];
1239
+ if (!A) throw p();
1240
+ if (A.allowed) {
1241
+ a = !1, N(), h();
1242
+ return;
1243
+ }
1244
+ T();
1245
+ } catch (A) {
1246
+ a = !1, N(), y(A);
1247
+ }
1248
+ };
1249
+ function f() {
1250
+ if (a) {
1251
+ if (document.visibilityState === "hidden") {
1252
+ l && clearTimeout(l), l = void 0;
1253
+ return;
1254
+ }
1255
+ T();
1256
+ }
1257
+ }
1258
+ document.addEventListener("visibilitychange", f);
1259
+ const q = n - e.now();
1260
+ return q <= 0 ? V() : (m = setTimeout(V, q), T()), {
1261
+ type: "frame",
1262
+ url: o.checkoutUrl,
1263
+ completion: k,
1264
+ cancel() {
1265
+ a && (a = !1, N(), h());
1266
+ }
1267
+ };
1268
+ }, R = {
1269
+ async open(o) {
1270
+ if (await e.ready(), e.session.snapshot?.accessProtocolVersion === 3) {
1271
+ const a = (await g([o.featureKey]))[o.featureKey];
1272
+ if (!a) throw p();
1273
+ if (a.nextAction === "RESOLVE_BUYER") {
1274
+ if (await s({
1275
+ featureKey: o.featureKey,
1276
+ reason: a.reason,
1277
+ action: "RESOLVE_BUYER",
1278
+ autoStart: !0,
1279
+ perform: () => t.start("IDENTIFY", o.featureKey)
1280
+ }) === "dismissed") throw r();
1281
+ } else if (!a.allowed && a.nextAction !== "CHECKOUT")
1282
+ throw new b({
1283
+ code: "CHECKOUT_UNAVAILABLE",
1284
+ message: "Checkout is not available for this feature.",
1285
+ retryable: !1
1286
+ });
1287
+ }
1288
+ const c = await M(o.featureKey, o);
1289
+ if (c.alreadyOwned) return c;
1290
+ if (await s({
1291
+ featureKey: o.featureKey,
1292
+ reason: "PURCHASE_REQUIRED",
1293
+ action: "CHECKOUT",
1294
+ autoStart: e.session.snapshot?.accessProtocolVersion === 3,
1295
+ perform: async () => _(c, o.featureKey)
1296
+ }) === "dismissed") throw r();
1297
+ return c;
1298
+ }
1299
+ }, P = {
1300
+ async getFeatures() {
1301
+ await e.ready();
1302
+ const o = L(
1303
+ (await e.session.request({
1304
+ method: "GET",
1305
+ path: "/v1/public/work-sdk/access/features"
1306
+ })).body
1307
+ );
1308
+ if (!Array.isArray(o.features) || o.features.length > 100)
1309
+ throw p();
1310
+ return o.features.map(
1311
+ (c) => Ae(c, e.session.snapshot?.accessProtocolVersion)
1312
+ );
1313
+ },
1314
+ async check(o) {
1315
+ const n = (await g([o]))[o];
1316
+ if (!n) throw p();
1317
+ return n;
1318
+ },
1319
+ checkMany: g,
1320
+ async require(o) {
1321
+ let c = await this.check(o);
1322
+ const n = /* @__PURE__ */ new Set();
1323
+ for (let a = 0; !c.allowed && c.nextAction && a < 6; a += 1) {
1324
+ const l = c.nextAction, m = `${c.reason}:${l}`;
1325
+ if (n.has(m)) return c;
1326
+ if (n.add(m), l === "FOLLOW" && e.session.snapshot?.accessProtocolVersion === 3) {
1327
+ await v.follow(), c = await this.check(o);
1328
+ continue;
1329
+ }
1330
+ const h = l === "FOLLOW" ? (await v.getState()).target : void 0, y = l === "CHECKOUT" ? await M(o) : void 0;
1331
+ if (y?.alreadyOwned) {
1332
+ c = await this.check(o);
1333
+ continue;
1334
+ }
1335
+ if (await s({
1336
+ featureKey: o,
1337
+ reason: c.reason,
1338
+ action: l,
1339
+ autoStart: e.session.snapshot?.accessProtocolVersion === 3,
1340
+ ...l === "SIGN_IN" ? U() : h ? { followTarget: h } : {},
1341
+ perform: async () => l === "SIGN_IN" ? d() : l === "RESOLVE_BUYER" ? t.start("IDENTIFY", o) : l === "FOLLOW" ? (await v.follow(), { type: "completed" }) : _(y, o)
1342
+ }) === "dismissed") return c;
1343
+ c = await this.check(o);
1344
+ }
1345
+ return c;
1346
+ },
1347
+ async refresh() {
1348
+ await e.ready();
1349
+ },
1350
+ restorePurchase: (o) => G("RESTORE", o),
1351
+ claimPurchase: (o) => G("CLAIM", o)
1352
+ };
1353
+ async function G(o, c) {
1354
+ if (await e.ready(), e.session.snapshot?.accessProtocolVersion !== 3)
1355
+ throw new b({
1356
+ code: "CAPABILITY_DISABLED",
1357
+ message: "This website has not enabled purchase recovery.",
1358
+ retryable: !1
1359
+ });
1360
+ if (await s({
1361
+ featureKey: c,
1362
+ reason: "BUYER_REQUIRED",
1363
+ action: "RESOLVE_BUYER",
1364
+ autoStart: !0,
1365
+ perform: () => t.start(o, c)
1366
+ }) === "dismissed") throw r();
1367
+ return P.check(c);
1368
+ }
1369
+ return { auth: D, follow: v, access: P, checkout: R };
1370
+ }
1371
+ class Oe {
1372
+ #e = new me();
1373
+ #r;
1374
+ #t;
1375
+ #a = new AbortController();
1376
+ #i;
1377
+ auth;
1378
+ access;
1379
+ checkout;
1380
+ /** Detaches the caller-signal listener; undefined when none was attached. */
1381
+ #o;
1382
+ constructor(t) {
1383
+ this.#t = t.config, this.#r = new pe({
1384
+ workKey: t.config.workKey,
1385
+ region: t.config.region,
1386
+ transport: t.transport,
1387
+ signal: this.#a.signal,
1388
+ ...t.now !== void 0 ? { now: t.now } : {}
1389
+ });
1390
+ const r = Se({
1391
+ session: this.#r,
1392
+ workKey: t.config.workKey,
1393
+ widgetOrigin: ne[t.config.region],
1394
+ now: t.now ?? (() => Date.now()),
1395
+ presenter: t.presenter,
1396
+ signal: this.#a.signal,
1397
+ ready: () => this.#n()
1398
+ });
1399
+ this.auth = r.auth, this.access = r.access, this.checkout = r.checkout;
1400
+ const i = t.config.signal;
1401
+ if (i) {
1402
+ const s = () => {
1403
+ this.#a.abort(
1404
+ i.reason instanceof Error ? i.reason : new DOMException("Caller signal aborted.", "AbortError")
1405
+ );
1406
+ };
1407
+ i.aborted ? s() : (i.addEventListener("abort", s, { once: !0 }), this.#o = () => {
1408
+ i.removeEventListener("abort", s);
1409
+ });
1410
+ }
1411
+ }
1412
+ get version() {
1413
+ return se;
1414
+ }
1415
+ get workKey() {
1416
+ return this.#t.workKey;
1417
+ }
1418
+ get region() {
1419
+ return this.#t.region;
1420
+ }
1421
+ get state() {
1422
+ return this.#e.state;
1423
+ }
1424
+ /** Internal: public API major, used by the loader registry namespace. */
1425
+ get apiMajor() {
1426
+ return ce;
1427
+ }
1428
+ ready() {
1429
+ return this.#e.destroyed ? Promise.reject(C()) : (this.#i || (this.#e.transition("READY"), this.#i = Promise.resolve()), this.#i);
1430
+ }
1431
+ async #n() {
1432
+ if (this.#e.destroyed) throw C();
1433
+ await this.ready();
1434
+ try {
1435
+ if (await this.#r.establish(), this.#e.destroyed) throw C();
1436
+ } catch (t) {
1437
+ throw this.#e.destroyed ? C() : (this.#r.invalidate(), t);
1438
+ }
1439
+ }
1440
+ hasCapability(t) {
1441
+ if (this.#e.destroyed) return !1;
1442
+ const r = this.#r.snapshot?.work.capabilities;
1443
+ return t === "danmaku" || t === "tip" || r?.includes(t) === !0;
1444
+ }
1445
+ /** Names of capabilities enabled for this work (empty before `ready()`). */
1446
+ get capabilities() {
1447
+ return this.#r.snapshot?.work.capabilities ?? [];
1448
+ }
1449
+ /**
1450
+ * Internal: mark one capability unavailable without taking down the client
1451
+ * (loader uses this when a feature chunk fails after the core is READY).
1452
+ */
1453
+ markDegraded() {
1454
+ this.#e.state === "READY" && this.#e.transition("DEGRADED");
1455
+ }
1456
+ /** Internal: session snapshot access for capability modules. */
1457
+ get sessionSnapshot() {
1458
+ return this.#r.snapshot;
1459
+ }
1460
+ destroy() {
1461
+ this.#e.destroyed || (this.#e.transition("DESTROYED"), this.#a.abort(C()), this.#r.destroy(), this.#e.clearListeners(), this.#i = void 0, this.#o?.(), this.#o = void 0);
1462
+ }
1463
+ }
1464
+ export {
1465
+ Oe as V,
1466
+ fe as a,
1467
+ ue as i,
1468
+ Le as r,
1469
+ Re as v
1470
+ };
1471
+ //# sourceMappingURL=client-DbPCnwf-.js.map