@viceme-ai/sdk 0.7.0 → 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.
@@ -1,1113 +0,0 @@
1
- import { a as R, V as v, c as k, i as Y } from "./errors-C7DfLKcF.js";
2
- import { a as W, B as $ } from "./build-endpoints-NrDmg6jf.js";
3
- import { S as Q, A as X } from "./version-CAPPYmfK.js";
4
- const J = /* @__PURE__ */ new Set(["cn", "global"]), Z = {
5
- cn: W.cn,
6
- global: W.global
7
- };
8
- function Ee(t) {
9
- return Z[t];
10
- }
11
- function ee(t) {
12
- return typeof t == "string" && /^wrk_(?:test|live)_[A-Za-z0-9_-]{4,119}$/.test(t);
13
- }
14
- function te(t) {
15
- return typeof t == "string" && J.has(t);
16
- }
17
- function Se(t) {
18
- if (typeof t != "object" || t === null)
19
- throw R("createViceMe expects a configuration object.");
20
- const e = t, i = /* @__PURE__ */ new Set(["workKey", "region", "signal"]);
21
- for (const r of Object.keys(e))
22
- if (!i.has(r))
23
- throw R(`Unknown configuration field "${r}".`);
24
- if (!ee(e.workKey))
25
- throw R(
26
- 'Configuration field "workKey" must start with "wrk_test_" or "wrk_live_".'
27
- );
28
- if (!te(e.region))
29
- throw R('Configuration field "region" must be "cn" or "global".');
30
- if (e.signal !== void 0 && !(e.signal instanceof AbortSignal))
31
- throw R('Configuration field "signal" must be an AbortSignal.');
32
- return {
33
- workKey: e.workKey,
34
- region: e.region,
35
- signal: e.signal
36
- };
37
- }
38
- const ie = {
39
- CREATED: ["READY", "DESTROYED"],
40
- READY: ["DEGRADED", "DESTROYED"],
41
- DEGRADED: ["DESTROYED"],
42
- DESTROYED: []
43
- };
44
- class re {
45
- #e = "CREATED";
46
- #t = /* @__PURE__ */ new Set();
47
- get state() {
48
- return this.#e;
49
- }
50
- get destroyed() {
51
- return this.#e === "DESTROYED";
52
- }
53
- transition(e) {
54
- if (e !== this.#e) {
55
- if (!ie[this.#e].includes(e))
56
- throw new v({
57
- code: "INTERNAL_ERROR",
58
- message: `Illegal lifecycle transition ${this.#e} -> ${e}.`,
59
- retryable: !1
60
- });
61
- this.#e = e;
62
- for (const i of this.#t) i(e);
63
- }
64
- }
65
- /** Any operation on a destroyed client must fail closed with this guard. */
66
- assertAlive() {
67
- if (this.destroyed) throw k();
68
- }
69
- subscribe(e) {
70
- return this.#t.add(e), () => {
71
- this.#t.delete(e);
72
- };
73
- }
74
- clearListeners() {
75
- this.#t.clear();
76
- }
77
- }
78
- function ae(t, e) {
79
- if (typeof t != "object" || t === null)
80
- throw C();
81
- const i = t;
82
- if (typeof i.workKey != "string" || !Array.isArray(i.capabilities) || !i.capabilities.every((s) => typeof s == "string"))
83
- throw C();
84
- if (i.workKey !== e)
85
- throw new v({
86
- code: "WORK_NOT_FOUND",
87
- message: "Work-session response did not match the requested work key.",
88
- retryable: !1
89
- });
90
- const r = {
91
- work: {
92
- key: i.workKey,
93
- capabilities: i.capabilities
94
- }
95
- };
96
- if (i.creator !== void 0 || i.work !== void 0) {
97
- const s = j(i.creator), w = j(i.work);
98
- if (typeof s.displayName != "string" || s.displayName.length === 0 || !z(s.avatarUrl) || !Number.isInteger(s.publishedWorkCount) || s.publishedWorkCount < 0 || typeof w.title != "string" || w.title.length === 0 || typeof w.summary != "string" || !z(w.coverUrl))
99
- throw C();
100
- r.work.creator = {
101
- displayName: s.displayName,
102
- avatarUrl: s.avatarUrl,
103
- publishedWorkCount: s.publishedWorkCount
104
- }, r.work.details = {
105
- title: w.title,
106
- summary: w.summary,
107
- coverUrl: w.coverUrl
108
- };
109
- }
110
- if (typeof i.token == "string" && (r.token = i.token), typeof i.expiresAt == "string") {
111
- const s = new Date(i.expiresAt).getTime();
112
- Number.isNaN(s) || (r.expiresAt = s);
113
- }
114
- return r;
115
- }
116
- function j(t) {
117
- if (typeof t != "object" || t === null) throw C();
118
- return t;
119
- }
120
- function z(t) {
121
- if (t === null) return !0;
122
- if (typeof t != "string") return !1;
123
- try {
124
- return new URL(t), !0;
125
- } catch {
126
- return !1;
127
- }
128
- }
129
- function C() {
130
- return new v({
131
- code: "INTERNAL_ERROR",
132
- message: "Malformed work-session response.",
133
- retryable: !0
134
- });
135
- }
136
- function oe() {
137
- return new v({
138
- code: "SESSION_EXPIRED",
139
- message: "The work session was invalidated before it completed.",
140
- retryable: !0
141
- });
142
- }
143
- class ne {
144
- #e;
145
- #t;
146
- #i;
147
- #r;
148
- #o = 0;
149
- #a = !1;
150
- constructor(e) {
151
- this.#e = e, this.#t = e.now ?? (() => Date.now());
152
- }
153
- get snapshot() {
154
- return this.#i;
155
- }
156
- /** True when the cached snapshot's server-provided expiry has passed. */
157
- #s() {
158
- const e = this.#i?.expiresAt;
159
- return e !== void 0 && e <= this.#t();
160
- }
161
- /**
162
- * Establish (or return the established) public session.
163
- *
164
- * A cached snapshot is reused only while it is unexpired; an expired
165
- * snapshot is dropped and re-authenticated. Concurrent callers share one
166
- * in-flight request (single flight).
167
- */
168
- establish() {
169
- if (this.#a) return Promise.reject(k());
170
- if (this.#i) {
171
- if (!this.#s()) return Promise.resolve(this.#i);
172
- this.#i = void 0;
173
- }
174
- if (this.#r) return this.#r;
175
- const e = this.#o, i = this.#e.transport.request({
176
- method: "POST",
177
- path: "/v1/public/work-sdk/sessions",
178
- body: { workKey: this.#e.workKey },
179
- signal: this.#e.signal,
180
- timeoutMs: this.#e.timeoutMs
181
- }).then((r) => {
182
- this.#c(e);
183
- const s = ae(r.body, this.#e.workKey);
184
- return this.#c(e), this.#i = s, s;
185
- }).finally(() => {
186
- this.#r === i && (this.#r = void 0);
187
- });
188
- return this.#r = i, i;
189
- }
190
- async request(e) {
191
- const i = await this.establish();
192
- if (!i.token) throw C();
193
- try {
194
- return await this.#l(e, i);
195
- } catch (r) {
196
- if (this.#a) throw k();
197
- if (!(r instanceof v) || r.code !== "SESSION_EXPIRED") throw r;
198
- this.#i === i && this.invalidate();
199
- const s = await this.establish();
200
- if (!s.token) throw C();
201
- return this.#l(e, s);
202
- }
203
- }
204
- authenticate(e) {
205
- if (this.#n(), !this.#i) throw C();
206
- this.#i = {
207
- ...this.#i,
208
- userToken: e.userToken,
209
- user: e.user
210
- };
211
- }
212
- async signOut() {
213
- this.#n(), this.invalidate(), await this.establish();
214
- }
215
- /** Drop the token; next `establish()` re-authenticates. */
216
- invalidate() {
217
- this.#o += 1, this.#i = void 0, this.#r = void 0;
218
- }
219
- /** Hard cleanup: forget the token and pending work. */
220
- destroy() {
221
- this.#a || (this.#a = !0, this.#o += 1, this.#i = void 0, this.#r = void 0);
222
- }
223
- #n() {
224
- if (this.#a) throw k();
225
- }
226
- #c(e) {
227
- if (this.#n(), e !== this.#o) throw oe();
228
- }
229
- async #l(e, i) {
230
- this.#n();
231
- try {
232
- const r = await this.#e.transport.request({
233
- ...e,
234
- authorization: i.token,
235
- userAuthorization: i.userToken,
236
- signal: this.#e.signal
237
- });
238
- return this.#n(), r;
239
- } catch (r) {
240
- throw this.#a ? k() : r;
241
- }
242
- }
243
- }
244
- const q = "viceme-access-layer", M = 50;
245
- function se(t) {
246
- switch (t) {
247
- case "SIGN_IN":
248
- return {
249
- description: "",
250
- label: "授权"
251
- };
252
- case "FOLLOW":
253
- return {
254
- description: "",
255
- label: "关注"
256
- };
257
- case "CHECKOUT":
258
- return {
259
- description: "",
260
- label: "打开支付"
261
- };
262
- }
263
- }
264
- function ce(t) {
265
- if (!Y(t)) return "操作未完成,请重试。";
266
- switch (t.code) {
267
- case "CONFIG_INVALID":
268
- return "微信授权配置无效,请稍后重试。";
269
- case "AUTH_CANCELLED":
270
- return "微信授权已取消,请重试。";
271
- case "SESSION_EXPIRED":
272
- return "授权会话已过期,请重试。";
273
- case "NETWORK_TIMEOUT":
274
- return "网络连接超时,请重试。";
275
- default:
276
- return t.requestId ? `操作未完成,请重试。请求 ID:${t.requestId}` : "操作未完成,请重试。";
277
- }
278
- }
279
- function le() {
280
- if (customElements.get(q)) return;
281
- class t extends HTMLElement {
282
- interaction;
283
- connectedCallback() {
284
- const i = se(this.interaction.action), r = this.attachShadow({ mode: "open" });
285
- r.innerHTML = `
286
- <style>
287
- :host {
288
- position: fixed;
289
- inset: 0;
290
- z-index: 2147483000;
291
- display: grid;
292
- align-items: end;
293
- color: #18181b;
294
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
295
- font-size: 16px;
296
- line-height: 1.5;
297
- }
298
- [data-viceme='backdrop'] {
299
- position: absolute;
300
- inset: 0;
301
- border: 0;
302
- border-radius: 0;
303
- background: transparent;
304
- }
305
- [data-viceme='panel'] {
306
- position: relative;
307
- box-sizing: border-box;
308
- display: flex;
309
- width: 100%;
310
- max-height: min(92dvh, 46rem);
311
- flex-direction: column;
312
- overflow: auto;
313
- border-radius: 1.25rem 1.25rem 0 0;
314
- background: #ffffff;
315
- color: #18181b;
316
- padding: 3.75rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom));
317
- box-shadow: 0 -1rem 3rem rgb(0 0 0 / 18%);
318
- }
319
- [data-viceme='content'] { display: flex; min-height: 0; flex-direction: column; }
320
- [data-viceme='close'] {
321
- position: absolute;
322
- top: 0.75rem;
323
- left: 0.75rem;
324
- width: 2.75rem;
325
- height: 2.75rem;
326
- border: 0;
327
- border-radius: 999px;
328
- padding: 0;
329
- background: transparent;
330
- color: #52525b;
331
- font-size: 2rem;
332
- font-weight: 400;
333
- line-height: 1;
334
- }
335
- [data-viceme='description'] { margin: 0.75rem 0 1.25rem; color: #71717a; line-height: 1.6; }
336
- [data-viceme='profile'] {
337
- display: none;
338
- margin: 0;
339
- border: 1px solid #e4e4e7;
340
- border-radius: 1rem;
341
- padding: 1.5rem;
342
- background: #ffffff;
343
- box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 6%);
344
- text-align: center;
345
- }
346
- [data-viceme='profile'][data-visible='true'] { display: block; }
347
- [data-viceme='avatar'] {
348
- display: block;
349
- width: 5.5rem;
350
- height: 5.5rem;
351
- margin: 0 auto 1rem;
352
- border-radius: 999px;
353
- object-fit: cover;
354
- background: #f4f4f5;
355
- }
356
- [data-viceme='avatar-fallback'] {
357
- display: grid;
358
- width: 5.5rem;
359
- height: 5.5rem;
360
- margin: 0 auto 1rem;
361
- place-items: center;
362
- border-radius: 999px;
363
- background: #f4f4f5;
364
- color: #18181b;
365
- font-size: 2rem;
366
- font-weight: 700;
367
- }
368
- [data-viceme='avatar'][hidden], [data-viceme='avatar-fallback'][hidden] { display: none; }
369
- [data-viceme='profile-summary'] {
370
- display: flex;
371
- min-width: 0;
372
- align-items: baseline;
373
- justify-content: center;
374
- gap: 0.5rem;
375
- }
376
- [data-viceme='profile-name'] { margin: 0; font-size: 1.375rem; font-weight: 700; }
377
- [data-viceme='profile-separator'], [data-viceme='profile-stats'] {
378
- color: #71717a;
379
- }
380
- [data-viceme='profile-description'] {
381
- margin: 0.25rem 0 0;
382
- overflow-wrap: anywhere;
383
- color: #71717a;
384
- }
385
- [data-viceme='profile-description']:empty { display: none; }
386
- [data-viceme='profile-stats'] {
387
- margin: 0;
388
- font-size: 0.875rem;
389
- }
390
- [data-viceme='profile-header'] { min-width: 0; }
391
- [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='description'] { display: none; }
392
- [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile'][data-visible='true'] {
393
- display: block;
394
- border: 0;
395
- padding: 0;
396
- background: transparent;
397
- box-shadow: none;
398
- text-align: center;
399
- }
400
- [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile-name'] {
401
- font-size: 1.125rem;
402
- }
403
- [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile-description'] {
404
- display: none;
405
- }
406
- [data-viceme='work'] {
407
- display: none;
408
- overflow: hidden;
409
- margin-top: 1.25rem;
410
- border: 1px solid #e4e4e7;
411
- border-radius: 1rem;
412
- background: #fafafa;
413
- text-align: left;
414
- }
415
- [data-viceme='work'][data-visible='true'] { display: block; }
416
- [data-viceme='work-cover'] {
417
- display: block;
418
- width: 100%;
419
- aspect-ratio: 16 / 9;
420
- object-fit: cover;
421
- background: #f4f4f5;
422
- }
423
- [data-viceme='work-cover'][hidden] { display: none; }
424
- [data-viceme='work-copy'] { padding: 1rem; }
425
- [data-viceme='work-title'] {
426
- margin: 0;
427
- color: #18181b;
428
- font-size: 1rem;
429
- font-weight: 700;
430
- line-height: 1.5;
431
- }
432
- [data-viceme='work-summary'] {
433
- display: -webkit-box;
434
- overflow: hidden;
435
- margin: 0.375rem 0 0;
436
- color: #71717a;
437
- font-size: 0.875rem;
438
- line-height: 1.5;
439
- -webkit-box-orient: vertical;
440
- -webkit-line-clamp: 2;
441
- }
442
- [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='action'] {
443
- width: 100%;
444
- }
445
- [data-viceme='actions'] {
446
- display: flex;
447
- justify-content: flex-end;
448
- gap: 0.75rem;
449
- margin-top: 1.25rem;
450
- }
451
- button {
452
- box-sizing: border-box;
453
- display: inline-flex;
454
- height: 3.25rem;
455
- align-items: center;
456
- justify-content: center;
457
- border-radius: 0.75rem;
458
- padding: 0.625rem 1rem;
459
- font: 600 1rem/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
460
- cursor: pointer;
461
- }
462
- button:focus-visible, iframe:focus-visible { outline: 2px solid #18181b; outline-offset: 2px; }
463
- [data-viceme='action'] {
464
- width: min(11rem, 48%);
465
- border: 1px solid #18181b;
466
- background: #18181b;
467
- color: #ffffff;
468
- }
469
- [data-viceme='action']:hover { background: #3f3f46; border-color: #3f3f46; }
470
- [data-viceme='actions'][data-single='true'] [data-viceme='action'] { width: 100%; }
471
- button:disabled { cursor: wait; opacity: 0.5; }
472
- button[hidden] { display: none; }
473
- [data-viceme='error'] { margin: 0.75rem 0 0; color: #b91c1c; font-size: 0.875rem; }
474
- [data-viceme='error']:empty { display: none; }
475
- [data-viceme='frame'] {
476
- display: none;
477
- width: 100%;
478
- min-height: 0;
479
- flex: 1 1 auto;
480
- border: 0;
481
- border-radius: 0.75rem;
482
- background: #ffffff;
483
- }
484
- [data-viceme='panel'][data-frame='true'] {
485
- height: min(92dvh, 46rem);
486
- max-height: 92dvh;
487
- overflow: hidden;
488
- }
489
- [data-viceme='panel'][data-frame='true'] [data-viceme='content'] { display: none; }
490
- [data-viceme='panel'][data-frame='true'] [data-viceme='frame'] { display: block; }
491
- @media (min-width: 48rem) {
492
- :host { place-items: center; padding: 1.5rem; }
493
- [data-viceme='panel'] {
494
- width: min(24rem, 100%);
495
- border-radius: 1.25rem;
496
- padding: 3.75rem 1.25rem 1.25rem;
497
- box-shadow: 0 1.5rem 4rem rgb(0 0 0 / 24%);
498
- }
499
- [data-viceme='panel'][data-frame='true'] { width: min(30rem, 100%); }
500
- [data-viceme='panel'][data-action='SIGN_IN'] { width: min(30rem, 100%); }
501
- [data-viceme='panel'][data-action='CHECKOUT'][data-frame='true'] {
502
- width: min(42rem, 100%);
503
- }
504
- }
505
- @media (prefers-reduced-motion: no-preference) {
506
- [data-viceme='panel'] { animation: viceme-enter 160ms ease-out; }
507
- @keyframes viceme-enter { from { opacity: 0; transform: translateY(1rem); } }
508
- }
509
- </style>
510
- <button data-viceme="backdrop" type="button" tabindex="-1" aria-label="关闭"></button>
511
- <section data-viceme="panel" role="dialog" aria-modal="true" aria-label="ViceMe 授权">
512
- <button data-viceme="close" type="button" aria-label="关闭">×</button>
513
- <div data-viceme="content">
514
- <p data-viceme="description"></p>
515
- <section data-viceme="profile" aria-label="创作者">
516
- <div data-viceme="profile-header">
517
- <img data-viceme="avatar" hidden />
518
- <span data-viceme="avatar-fallback" aria-hidden="true"></span>
519
- <div data-viceme="profile-summary">
520
- <p data-viceme="profile-name"></p>
521
- <span data-viceme="profile-separator" aria-hidden="true">·</span>
522
- <p data-viceme="profile-stats"></p>
523
- </div>
524
- </div>
525
- <p data-viceme="profile-description"></p>
526
- </section>
527
- <article data-viceme="work">
528
- <img data-viceme="work-cover" hidden />
529
- <div data-viceme="work-copy">
530
- <p data-viceme="work-title"></p>
531
- <p data-viceme="work-summary"></p>
532
- </div>
533
- </article>
534
- <p data-viceme="error" role="alert" aria-live="polite"></p>
535
- <div data-viceme="actions">
536
- <button data-viceme="action" type="button"></button>
537
- </div>
538
- </div>
539
- <iframe data-viceme="frame" title="" referrerpolicy="no-referrer" allow="payment"></iframe>
540
- </section>
541
- `;
542
- const s = r.querySelector("[data-viceme='panel']");
543
- s.dataset.action = this.interaction.action, s.dataset.frame = "false";
544
- const w = r.querySelector("[data-viceme='description']");
545
- w.textContent = i.description;
546
- const f = r.querySelector("[data-viceme='action']"), L = f.parentElement, D = r.querySelector("[data-viceme='close']"), T = r.querySelector("[data-viceme='backdrop']"), O = r.querySelector("[data-viceme='error']"), N = r.querySelector("[data-viceme='frame']"), U = r.querySelector("[data-viceme='profile']"), _ = r.querySelector("[data-viceme='avatar']"), K = r.querySelector("[data-viceme='avatar-fallback']"), a = r.querySelector("[data-viceme='profile-name']"), n = r.querySelector(
547
- "[data-viceme='profile-description']"
548
- ), d = r.querySelector("[data-viceme='profile-stats']"), o = r.querySelector("[data-viceme='work']"), l = r.querySelector("[data-viceme='work-cover']"), g = r.querySelector("[data-viceme='work-title']"), S = r.querySelector("[data-viceme='work-summary']");
549
- f.textContent = i.label, f.hidden = !1, L.dataset.single = "true";
550
- const A = i.label;
551
- N.title = this.interaction.action === "SIGN_IN" ? "登录授权" : "支付";
552
- const m = this.interaction.followTarget;
553
- if (m) {
554
- s.setAttribute(
555
- "aria-label",
556
- this.interaction.action === "SIGN_IN" ? `授权 ${m.displayName}` : `关注 ${m.displayName}`
557
- ), U.dataset.visible = "true", a.textContent = m.displayName;
558
- const c = [...m.description ?? ""];
559
- n.textContent = c.length > M ? `${c.slice(0, M).join("")}…` : c.join(""), c.length > M && (n.title = m.description), d.textContent = `${m.workCount} 个作品`, K.textContent = m.displayName.trim().slice(0, 1) || "V", m.avatarUrl && (_.src = m.avatarUrl, _.alt = `${m.displayName}的头像`, _.hidden = !1, K.hidden = !0);
560
- }
561
- const p = this.interaction.work;
562
- p && (o.dataset.visible = "true", g.textContent = p.title, S.textContent = p.summary, p.coverUrl && (l.src = p.coverUrl, l.alt = p.title, l.hidden = !1));
563
- let b = null, E = !1;
564
- const y = (c) => {
565
- E || (E = !0, this.interaction.signal?.removeEventListener("abort", u), this.dispatchEvent(new CustomEvent("viceme:access-layer-close", { detail: c })));
566
- }, u = () => {
567
- b?.cancel(), y("dismissed");
568
- };
569
- this.interaction.signal?.addEventListener("abort", u, { once: !0 }), this.interaction.signal?.aborted && queueMicrotask(u), T.addEventListener("click", u), D.addEventListener("click", u), this.addEventListener("keydown", (c) => {
570
- if (c.key === "Escape" && u(), c.key === "Tab") {
571
- if (c.preventDefault(), b?.type === "frame") {
572
- N.focus();
573
- return;
574
- }
575
- const x = [D, ...f.hidden ? [] : [f]].filter((G) => !G.disabled && !G.hidden);
576
- if (x.length === 0) return;
577
- const V = x.indexOf(r.activeElement), B = c.shiftKey ? -1 : 1;
578
- x[(V + B + x.length) % x.length]?.focus();
579
- }
580
- });
581
- const P = async () => {
582
- f.disabled = !0, f.setAttribute("aria-busy", "true"), f.textContent = "正在打开…", O.textContent = "";
583
- try {
584
- const c = await this.interaction.perform();
585
- if (E || this.interaction.signal?.aborted) {
586
- c.type !== "completed" && c.cancel();
587
- return;
588
- }
589
- c.type === "frame" ? (b = c, s.dataset.frame = "true", N.src = c.url, N.focus(), await c.completion) : c.type === "external" && (b = c, await c.completion), y("acted");
590
- } catch (c) {
591
- if (E) return;
592
- b?.cancel(), b = null, s.dataset.frame = "false", N.removeAttribute("src"), O.textContent = ce(c), f.hidden = !1, f.disabled = !1, f.removeAttribute("aria-busy"), f.textContent = A, f.focus();
593
- }
594
- };
595
- f.addEventListener("click", P), queueMicrotask(() => f.focus());
596
- }
597
- }
598
- customElements.define(q, t);
599
- }
600
- const de = async (t) => {
601
- if (typeof document > "u" || typeof customElements > "u" || t.signal?.aborted) return "dismissed";
602
- le();
603
- const e = document.createElement(q);
604
- e.interaction = t;
605
- const i = document.documentElement.style.overflow, r = document.activeElement instanceof HTMLElement ? document.activeElement : null;
606
- document.documentElement.style.overflow = "hidden", document.body.append(e);
607
- try {
608
- return await new Promise((s) => {
609
- e.addEventListener(
610
- "viceme:access-layer-close",
611
- (w) => s(w.detail),
612
- { once: !0 }
613
- );
614
- });
615
- } finally {
616
- e.remove(), document.documentElement.style.overflow = i, r?.focus();
617
- }
618
- };
619
- function I(t) {
620
- if (typeof t != "object" || t === null) throw h();
621
- return t;
622
- }
623
- function h() {
624
- return new v({
625
- code: "INTERNAL_ERROR",
626
- message: "Malformed public API response.",
627
- retryable: !0
628
- });
629
- }
630
- function ue(t) {
631
- const e = I(t);
632
- if (typeof e.id != "string" || !(typeof e.displayName == "string" || e.displayName === null) || !(typeof e.avatarUrl == "string" || e.avatarUrl === null))
633
- throw h();
634
- return {
635
- subject: e.id,
636
- nickname: e.displayName,
637
- avatarUrl: e.avatarUrl
638
- };
639
- }
640
- function H(t) {
641
- const e = I(t);
642
- if (typeof e.following != "boolean" || !(typeof e.followedAt == "string" || e.followedAt === null))
643
- throw h();
644
- const i = I(e.creator);
645
- if (typeof i.displayName != "string" || !(typeof i.avatarUrl == "string" || i.avatarUrl === null) || !(typeof i.description == "string" || i.description === null) || !Number.isInteger(i.publishedWorkCount) || i.publishedWorkCount < 0)
646
- throw h();
647
- return {
648
- following: e.following,
649
- followedAt: e.followedAt,
650
- target: {
651
- kind: "CREATOR",
652
- displayName: i.displayName,
653
- avatarUrl: i.avatarUrl,
654
- description: i.description,
655
- workCount: i.publishedWorkCount
656
- }
657
- };
658
- }
659
- function fe(t) {
660
- const e = I(t), i = /* @__PURE__ */ new Set([
661
- "PUBLIC",
662
- "OWNER",
663
- "FOLLOWING",
664
- "ENTITLED",
665
- "AUTH_REQUIRED",
666
- "FOLLOW_REQUIRED",
667
- "PURCHASE_REQUIRED",
668
- "FEATURE_NOT_FOUND",
669
- "FEATURE_DISABLED"
670
- ]), r = /* @__PURE__ */ new Set([null, "SIGN_IN", "FOLLOW", "CHECKOUT"]);
671
- if (typeof e.allowed != "boolean" || typeof e.reason != "string" || !i.has(e.reason) || !r.has(e.nextAction))
672
- throw h();
673
- return {
674
- allowed: e.allowed,
675
- reason: e.reason,
676
- nextAction: e.nextAction
677
- };
678
- }
679
- function me(t) {
680
- const e = I(t);
681
- if (typeof e.featureKey != "string" || !/^[a-z][a-z0-9_-]{1,63}$/.test(e.featureKey) || typeof e.title != "string" || e.title.trim().length === 0 || e.title.length > 120 || !(e.policyType === "PUBLIC" || e.policyType === "FOLLOW_OWNER" || e.policyType === "WORK_ENTITLEMENT"))
682
- throw h();
683
- const i = e.price === null ? null : I(e.price);
684
- if (i !== null && (!Number.isInteger(i.amountCents) || i.amountCents <= 0 || i.currency !== "CNY") || e.policyType === "WORK_ENTITLEMENT" != (i !== null))
685
- throw h();
686
- return {
687
- featureKey: e.featureKey,
688
- title: e.title,
689
- policy: { type: e.policyType },
690
- price: i === null ? null : { amountCents: i.amountCents, currency: "CNY" }
691
- };
692
- }
693
- function he() {
694
- const t = crypto.getRandomValues(new Uint8Array(32));
695
- return pe(t);
696
- }
697
- function pe(t) {
698
- let e = "";
699
- for (const i of t) e += String.fromCharCode(i);
700
- return btoa(e).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
701
- }
702
- function ye() {
703
- return typeof document < "u" && document.documentElement.lang.toLowerCase() === "en-us" ? "en-US" : "zh-CN";
704
- }
705
- function we(t) {
706
- const e = () => new v({
707
- code: "AUTH_CANCELLED",
708
- message: "The interactive action was cancelled.",
709
- retryable: !1
710
- }), i = (a) => {
711
- if (t.signal.aborted) return Promise.reject(k());
712
- let n;
713
- const d = new Promise((l, g) => {
714
- n = () => g(k()), t.signal.addEventListener("abort", n, { once: !0 }), t.signal.aborted && n();
715
- });
716
- let o;
717
- try {
718
- o = (t.presenter ?? de)({
719
- ...a,
720
- signal: t.signal
721
- });
722
- } catch (l) {
723
- o = Promise.reject(l);
724
- }
725
- return Promise.race([o, d]).then((l) => {
726
- if (t.signal.aborted) throw k();
727
- return l;
728
- }).finally(() => {
729
- n && t.signal.removeEventListener("abort", n);
730
- });
731
- }, r = (a, n, d, o, l, g) => {
732
- if (typeof window > "u")
733
- throw new v({
734
- code: "CONFIG_INVALID",
735
- message: "Interactive access requires a browser window.",
736
- retryable: !1
737
- });
738
- let S = !0, A, m;
739
- const p = () => {
740
- S && (S = !1, window.removeEventListener("message", E));
741
- }, b = new Promise((y, u) => {
742
- A = y, m = u;
743
- }), E = (y) => {
744
- if (!S || y.origin !== n || typeof y.data != "object" || y.data === null) return;
745
- const u = y.data;
746
- if (!(u.workKey !== t.workKey || u.channel !== d)) {
747
- if (u.type === `viceme:${o}:ready`) {
748
- y.source && "postMessage" in y.source && y.source.postMessage(
749
- {
750
- type: `viceme:${o}:init`,
751
- workKey: t.workKey,
752
- channel: d,
753
- ...l
754
- },
755
- n
756
- );
757
- return;
758
- }
759
- if (u.type === `viceme:${o}:cancelled`) {
760
- p(), m(e());
761
- return;
762
- }
763
- u.type === `viceme:${o}:complete` && (p(), g(u).then(A, m));
764
- }
765
- };
766
- return window.addEventListener("message", E), {
767
- type: "frame",
768
- url: a,
769
- completion: b,
770
- cancel() {
771
- p(), A();
772
- }
773
- };
774
- }, s = async () => {
775
- if (await t.ready(), typeof window > "u")
776
- throw new v({
777
- code: "CONFIG_INVALID",
778
- message: "Interactive access requires a browser window.",
779
- retryable: !1
780
- });
781
- const a = he(), n = new URL("/sdk/login", t.widgetOrigin);
782
- n.search = new URLSearchParams({
783
- workKey: t.workKey,
784
- channel: a,
785
- parentOrigin: window.location.origin,
786
- locale: ye()
787
- }).toString();
788
- const d = t.session.snapshot?.token;
789
- if (!d) throw h();
790
- return r(
791
- n.toString(),
792
- t.widgetOrigin,
793
- a,
794
- "auth",
795
- { workSessionToken: d },
796
- async (o) => {
797
- if (typeof o.userToken != "string")
798
- throw h();
799
- t.session.authenticate({ userToken: o.userToken, user: ue(o.user) });
800
- }
801
- );
802
- }, w = async () => (await t.ready(), H(
803
- (await t.session.request({ method: "GET", path: "/v1/public/work-sdk/follow" })).body
804
- )), f = async () => (await t.ready(), H(
805
- (await t.session.request({ method: "PUT", path: "/v1/public/work-sdk/follow" })).body
806
- )), L = () => {
807
- const a = t.session.snapshot?.work;
808
- return {
809
- ...a?.creator ? {
810
- followTarget: {
811
- kind: "CREATOR",
812
- displayName: a.creator.displayName,
813
- avatarUrl: a.creator.avatarUrl,
814
- description: null,
815
- workCount: a.creator.publishedWorkCount
816
- }
817
- } : {},
818
- ...a?.details ? { work: a.details } : {}
819
- };
820
- }, D = {
821
- async getState() {
822
- await t.ready();
823
- const a = t.session.snapshot?.user ?? null;
824
- return { authenticated: a !== null, user: a };
825
- },
826
- async signIn() {
827
- if (await t.ready(), await i({
828
- featureKey: "auth",
829
- reason: "AUTH_REQUIRED",
830
- action: "SIGN_IN",
831
- ...L(),
832
- perform: s
833
- }) === "dismissed") throw e();
834
- return this.getState();
835
- },
836
- async signOut() {
837
- await t.ready(), await t.session.signOut();
838
- }
839
- }, T = {
840
- getState: w,
841
- follow: f,
842
- unfollow: async () => {
843
- throw new v({
844
- code: "CAPABILITY_DISABLED",
845
- message: "Unfollow is not exposed by website access.",
846
- retryable: !1
847
- });
848
- }
849
- }, O = async (a) => {
850
- await t.ready();
851
- const n = I(
852
- (await t.session.request({
853
- method: "POST",
854
- path: "/v1/public/work-sdk/access/check",
855
- body: { featureKeys: a }
856
- })).body
857
- ), d = I(n.decisions);
858
- return Object.fromEntries(
859
- Object.entries(d).map(([o, l]) => [o, fe(l)])
860
- );
861
- }, N = async (a, n = {}) => {
862
- await t.ready();
863
- const d = {
864
- featureKey: a,
865
- locale: n.locale ?? "zh-CN"
866
- }, o = I(
867
- (await t.session.request({
868
- method: "POST",
869
- path: "/v1/public/work-sdk/checkout",
870
- body: d
871
- })).body
872
- );
873
- if (typeof o.checkoutUrl != "string" || typeof o.alreadyOwned != "boolean" || !(o.expiresAt === null || typeof o.expiresAt == "string" && !Number.isNaN(Date.parse(o.expiresAt))) || o.alreadyOwned !== (o.expiresAt === null))
874
- throw h();
875
- let l;
876
- try {
877
- l = new URL(o.checkoutUrl);
878
- } catch {
879
- throw h();
880
- }
881
- if (!o.alreadyOwned && (l.protocol !== "https:" || l.origin !== t.widgetOrigin))
882
- throw h();
883
- return {
884
- checkoutUrl: o.checkoutUrl,
885
- alreadyOwned: o.alreadyOwned,
886
- expiresAt: o.expiresAt
887
- };
888
- }, U = (a, n) => {
889
- if (a.alreadyOwned) return { type: "completed" };
890
- const d = Date.parse(a.expiresAt);
891
- if (typeof window > "u")
892
- throw new v({
893
- code: "CONFIG_INVALID",
894
- message: "Hosted checkout requires a browser window.",
895
- retryable: !1
896
- });
897
- let o = !0, l, g, S, A;
898
- const m = new Promise((c, F) => {
899
- S = c, A = F;
900
- }), p = () => {
901
- l && clearTimeout(l), g && clearTimeout(g), document.removeEventListener("visibilitychange", u);
902
- }, b = () => {
903
- o && (o = !1, p(), A(
904
- new v({
905
- code: "SESSION_EXPIRED",
906
- message: "Hosted checkout session expired.",
907
- retryable: !0
908
- })
909
- ));
910
- }, E = () => {
911
- if (!o || document.visibilityState === "hidden") return;
912
- const c = d - t.now();
913
- if (c <= 0) {
914
- b();
915
- return;
916
- }
917
- l = setTimeout(() => {
918
- y();
919
- }, Math.min(1500, c));
920
- }, y = async () => {
921
- if (o)
922
- try {
923
- const c = (await O([n]))[n];
924
- if (!c) throw h();
925
- if (c.allowed) {
926
- o = !1, p(), S();
927
- return;
928
- }
929
- E();
930
- } catch (c) {
931
- o = !1, p(), A(c);
932
- }
933
- };
934
- function u() {
935
- if (o) {
936
- if (document.visibilityState === "hidden") {
937
- l && clearTimeout(l), l = void 0;
938
- return;
939
- }
940
- E();
941
- }
942
- }
943
- document.addEventListener("visibilitychange", u);
944
- const P = d - t.now();
945
- return P <= 0 ? b() : (g = setTimeout(b, P), E()), {
946
- type: "frame",
947
- url: a.checkoutUrl,
948
- completion: m,
949
- cancel() {
950
- o && (o = !1, p(), S());
951
- }
952
- };
953
- };
954
- return { auth: D, follow: T, access: {
955
- async getFeatures() {
956
- await t.ready();
957
- const a = I(
958
- (await t.session.request({
959
- method: "GET",
960
- path: "/v1/public/work-sdk/access/features"
961
- })).body
962
- );
963
- if (!Array.isArray(a.features) || a.features.length > 100)
964
- throw h();
965
- return a.features.map(me);
966
- },
967
- async check(a) {
968
- const d = (await O([a]))[a];
969
- if (!d) throw h();
970
- return d;
971
- },
972
- checkMany: O,
973
- async require(a) {
974
- let n = await this.check(a);
975
- for (let d = 0; !n.allowed && n.nextAction && d < 3; d += 1) {
976
- const o = n.nextAction, l = o === "FOLLOW" ? (await T.getState()).target : void 0, g = o === "CHECKOUT" ? await N(a) : void 0;
977
- if (g?.alreadyOwned) {
978
- n = await this.check(a);
979
- continue;
980
- }
981
- if (await i({
982
- featureKey: a,
983
- reason: n.reason,
984
- action: o,
985
- ...o === "SIGN_IN" ? L() : l ? { followTarget: l } : {},
986
- perform: async () => o === "SIGN_IN" ? s() : o === "FOLLOW" ? (await T.follow(), { type: "completed" }) : U(g, a)
987
- }) === "dismissed") return n;
988
- n = await this.check(a);
989
- }
990
- return n;
991
- },
992
- async refresh() {
993
- await t.ready();
994
- }
995
- }, checkout: {
996
- async open(a) {
997
- const n = await N(a.featureKey, a);
998
- if (n.alreadyOwned) return n;
999
- if (await i({
1000
- featureKey: a.featureKey,
1001
- reason: "PURCHASE_REQUIRED",
1002
- action: "CHECKOUT",
1003
- perform: async () => U(n, a.featureKey)
1004
- }) === "dismissed") throw e();
1005
- return n;
1006
- }
1007
- } };
1008
- }
1009
- class ge extends DOMException {
1010
- constructor() {
1011
- super("ViceMe client destroyed.", "AbortError");
1012
- }
1013
- }
1014
- class Ie {
1015
- #e = new re();
1016
- #t;
1017
- #i;
1018
- #r = new AbortController();
1019
- #o;
1020
- auth;
1021
- access;
1022
- checkout;
1023
- /** Detaches the caller-signal listener; undefined when none was attached. */
1024
- #a;
1025
- constructor(e) {
1026
- this.#i = e.config, this.#t = new ne({
1027
- workKey: e.config.workKey,
1028
- transport: e.transport,
1029
- signal: this.#r.signal,
1030
- ...e.now !== void 0 ? { now: e.now } : {}
1031
- });
1032
- const i = we({
1033
- session: this.#t,
1034
- workKey: e.config.workKey,
1035
- widgetOrigin: $[e.config.region],
1036
- now: e.now ?? (() => Date.now()),
1037
- presenter: e.presenter,
1038
- signal: this.#r.signal,
1039
- ready: () => this.#s()
1040
- });
1041
- this.auth = i.auth, this.access = i.access, this.checkout = i.checkout;
1042
- const r = e.config.signal;
1043
- if (r) {
1044
- const s = () => {
1045
- this.#r.abort(
1046
- r.reason instanceof Error ? r.reason : new DOMException("Caller signal aborted.", "AbortError")
1047
- );
1048
- };
1049
- r.aborted ? s() : (r.addEventListener("abort", s, { once: !0 }), this.#a = () => {
1050
- r.removeEventListener("abort", s);
1051
- });
1052
- }
1053
- }
1054
- get version() {
1055
- return Q;
1056
- }
1057
- get workKey() {
1058
- return this.#i.workKey;
1059
- }
1060
- get region() {
1061
- return this.#i.region;
1062
- }
1063
- get state() {
1064
- return this.#e.state;
1065
- }
1066
- /** Internal: public API major, used by the loader registry namespace. */
1067
- get apiMajor() {
1068
- return X;
1069
- }
1070
- ready() {
1071
- return this.#e.destroyed ? Promise.reject(k()) : (this.#o || (this.#e.transition("READY"), this.#o = Promise.resolve()), this.#o);
1072
- }
1073
- async #s() {
1074
- if (this.#e.destroyed) throw k();
1075
- await this.ready();
1076
- try {
1077
- if (await this.#t.establish(), this.#e.destroyed) throw k();
1078
- } catch (e) {
1079
- throw this.#e.destroyed ? k() : (this.#t.invalidate(), e);
1080
- }
1081
- }
1082
- hasCapability(e) {
1083
- if (this.#e.destroyed) return !1;
1084
- const i = this.#t.snapshot?.work.capabilities;
1085
- return e === "danmaku" || e === "tip" || i?.includes(e) === !0;
1086
- }
1087
- /** Names of capabilities enabled for this work (empty before `ready()`). */
1088
- get capabilities() {
1089
- return this.#t.snapshot?.work.capabilities ?? [];
1090
- }
1091
- /**
1092
- * Internal: mark one capability unavailable without taking down the client
1093
- * (loader uses this when a feature chunk fails after the core is READY).
1094
- */
1095
- markDegraded() {
1096
- this.#e.state === "READY" && this.#e.transition("DEGRADED");
1097
- }
1098
- /** Internal: session snapshot access for capability modules. */
1099
- get sessionSnapshot() {
1100
- return this.#t.snapshot;
1101
- }
1102
- destroy() {
1103
- this.#e.destroyed || (this.#e.transition("DESTROYED"), this.#r.abort(new ge()), this.#t.destroy(), this.#e.clearListeners(), this.#o = void 0, this.#a?.(), this.#a = void 0);
1104
- }
1105
- }
1106
- export {
1107
- Ie as V,
1108
- te as a,
1109
- ee as i,
1110
- Ee as r,
1111
- Se as v
1112
- };
1113
- //# sourceMappingURL=client-C1Sw400H.js.map