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