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