@bunnyland/ui-web 0.2.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 (57) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +211 -0
  3. package/assets/bunnyland-api.js +345 -0
  4. package/assets/bunnyland-play.js +1223 -0
  5. package/assets/bunnyland-ui.css +1634 -0
  6. package/assets/bunnyland-ui.js +795 -0
  7. package/dist/admin-widgets.d.ts +31 -0
  8. package/dist/admin-widgets.d.ts.map +1 -0
  9. package/dist/admin-widgets.js +100 -0
  10. package/dist/admin-widgets.js.map +1 -0
  11. package/dist/api.d.ts +37 -0
  12. package/dist/api.d.ts.map +1 -0
  13. package/dist/api.js +125 -0
  14. package/dist/api.js.map +1 -0
  15. package/dist/index.d.ts +7 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +7 -0
  18. package/dist/play.d.ts +265 -0
  19. package/dist/play.d.ts.map +1 -0
  20. package/dist/play.js +806 -0
  21. package/dist/play.js.map +1 -0
  22. package/dist/player-widgets.d.ts +11 -0
  23. package/dist/player-widgets.d.ts.map +1 -0
  24. package/dist/player-widgets.js +21 -0
  25. package/dist/player-widgets.js.map +1 -0
  26. package/dist/preact/auth.d.ts +37 -0
  27. package/dist/preact/auth.d.ts.map +1 -0
  28. package/dist/preact/components.d.ts +58 -0
  29. package/dist/preact/components.d.ts.map +1 -0
  30. package/dist/preact/theme.d.ts +16 -0
  31. package/dist/preact/theme.d.ts.map +1 -0
  32. package/dist/preact.d.ts +4 -0
  33. package/dist/preact.d.ts.map +1 -0
  34. package/dist/preact.js +488 -0
  35. package/dist/preact.js.map +1 -0
  36. package/dist/theme.d.ts +31 -0
  37. package/dist/theme.d.ts.map +1 -0
  38. package/dist/theme.js +165 -0
  39. package/dist/theme.js.map +1 -0
  40. package/dist/widgets.d.ts +7 -0
  41. package/dist/widgets.d.ts.map +1 -0
  42. package/dist/widgets.js +31 -0
  43. package/dist/widgets.js.map +1 -0
  44. package/docs/admin/custom-web-themes.md +112 -0
  45. package/docs/developer/design-language.md +116 -0
  46. package/package.json +101 -0
  47. package/src/admin-widgets.ts +189 -0
  48. package/src/api.ts +193 -0
  49. package/src/index.ts +6 -0
  50. package/src/play.ts +1151 -0
  51. package/src/player-widgets.ts +29 -0
  52. package/src/preact/auth.tsx +338 -0
  53. package/src/preact/components.tsx +249 -0
  54. package/src/preact/theme.tsx +72 -0
  55. package/src/preact.ts +3 -0
  56. package/src/theme.ts +225 -0
  57. package/src/widgets.ts +41 -0
package/dist/play.js ADDED
@@ -0,0 +1,806 @@
1
+ import { ApiError as e, assertSameOriginBase as t, claimHeaders as n, getClientId as r, getPlayerAuth as i, mediaUrl as a, mergePlayerHeaders as o, parseJsonResponse as s, sendJson as c, setClientId as l, socketUrl as u } from "./api.js";
2
+ import { storageGet as d, storageRemove as f, storageSet as p } from "./widgets.js";
3
+ //#region src/play.ts
4
+ var m = {
5
+ REQUEST_EMOJI: "๐Ÿ“ท",
6
+ ACK_EMOJI: "๐Ÿ‘€",
7
+ DELIVER_EMOJI: "๐Ÿ“ธ",
8
+ FAIL_EMOJI: "โš ๏ธ",
9
+ REQUEST_LABEL: "Request image"
10
+ }, h = {
11
+ room: "๐Ÿ ",
12
+ character: "๐Ÿฐ",
13
+ container: "๐Ÿ“ฆ",
14
+ item: "โœฆ",
15
+ door: "๐Ÿšช",
16
+ food: "๐ŸŽ",
17
+ water: "๐Ÿ’ง",
18
+ chair: "๐Ÿช‘",
19
+ table: "๐Ÿชต",
20
+ bed: "๐Ÿ›",
21
+ art: "๐Ÿ–ผ",
22
+ window: "๐ŸชŸ",
23
+ other: "โฌก"
24
+ }, g = {
25
+ look: "๐Ÿ‘๏ธ",
26
+ inspect: "๐Ÿ”Ž",
27
+ move: "โžก๏ธ",
28
+ take: "๐Ÿคฒ",
29
+ put: "๐Ÿ“ฅ",
30
+ drop: "๐Ÿ“ค",
31
+ open: "๐Ÿšช",
32
+ close: "๐Ÿšช",
33
+ lock: "๐Ÿ”’",
34
+ unlock: "๐Ÿ”“",
35
+ hold: "โœŠ",
36
+ unhold: "๐Ÿซณ",
37
+ wear: "๐Ÿงฅ",
38
+ remove: "๐Ÿงฅ",
39
+ use: "๐Ÿ› ๏ธ",
40
+ write: "โœ๏ธ",
41
+ sleep: "๐Ÿ’ค",
42
+ wake: "โ˜€๏ธ",
43
+ wait: "โณ",
44
+ "move-sprite": "๐ŸŽฏ",
45
+ say: "๐Ÿ’ฌ",
46
+ tell: "๐Ÿ—ฃ๏ธ",
47
+ "take-note": "๐Ÿ“",
48
+ remember: "๐Ÿง ",
49
+ forget: "๐Ÿงน",
50
+ reflect: "๐Ÿ’ญ",
51
+ ignite: "๐Ÿ”ฅ",
52
+ extinguish: "๐Ÿงฏ",
53
+ "water-crop": "๐Ÿ’ง",
54
+ eat: "๐Ÿฝ๏ธ",
55
+ drink: "๐Ÿ’ง",
56
+ craft: "๐Ÿ› ๏ธ",
57
+ attack: "โš”๏ธ",
58
+ defend: "๐Ÿ›ก๏ธ",
59
+ "cast-spell": "โœจ",
60
+ scan: "๐Ÿ“ก",
61
+ jump: "๐Ÿš€"
62
+ }, _ = [
63
+ ["move", "โžก๏ธ"],
64
+ ["travel", "๐Ÿงญ"],
65
+ ["enter", "๐Ÿšช"],
66
+ ["leave", "๐Ÿšช"],
67
+ ["open", "๐Ÿšช"],
68
+ ["close", "๐Ÿšช"],
69
+ ["lock", "๐Ÿ”’"],
70
+ ["unlock", "๐Ÿ”“"],
71
+ ["search", "๐Ÿ”Ž"],
72
+ ["inspect", "๐Ÿ”Ž"],
73
+ ["scan", "๐Ÿ“ก"],
74
+ ["survey", "๐Ÿ—บ๏ธ"],
75
+ ["study", "๐Ÿ“š"],
76
+ ["learn", "๐Ÿ“š"],
77
+ ["read", "๐Ÿ“–"],
78
+ ["write", "โœ๏ธ"],
79
+ ["say", "๐Ÿ’ฌ"],
80
+ ["tell", "๐Ÿ—ฃ๏ธ"],
81
+ ["ask", "โ“"],
82
+ ["remember", "๐Ÿง "],
83
+ ["reflect", "๐Ÿ’ญ"],
84
+ ["note", "๐Ÿ“"],
85
+ ["take", "๐Ÿคฒ"],
86
+ ["collect", "๐Ÿคฒ"],
87
+ ["claim", "๐Ÿณ๏ธ"],
88
+ ["drop", "๐Ÿ“ค"],
89
+ ["put", "๐Ÿ“ฅ"],
90
+ ["store", "๐Ÿ“ฅ"],
91
+ ["retrieve", "๐Ÿ“ค"],
92
+ ["haul", "๐Ÿ“ฆ"],
93
+ ["cargo", "๐Ÿ“ฆ"],
94
+ ["deliver", "๐Ÿ“ฆ"],
95
+ ["buy", "๐Ÿ›’"],
96
+ ["sell", "๐Ÿท๏ธ"],
97
+ ["trade", "๐Ÿค"],
98
+ ["pay", "๐Ÿ’ฐ"],
99
+ ["work", "๐Ÿ’ผ"],
100
+ ["job", "๐Ÿ’ผ"],
101
+ ["craft", "๐Ÿ› ๏ธ"],
102
+ ["repair", "๐Ÿ› ๏ธ"],
103
+ ["build", "๐Ÿ—๏ธ"],
104
+ ["upgrade", "โฌ†๏ธ"],
105
+ ["install", "๐Ÿ”ง"],
106
+ ["machine", "โš™๏ธ"],
107
+ ["power", "โšก"],
108
+ ["water", "๐Ÿ’ง"],
109
+ ["drink", "๐Ÿ’ง"],
110
+ ["plant", "๐ŸŒฑ"],
111
+ ["harvest", "๐ŸŒพ"],
112
+ ["forage", "๐ŸŒฟ"],
113
+ ["egg", "๐Ÿฅš"],
114
+ ["feed", "๐Ÿฝ๏ธ"],
115
+ ["eat", "๐Ÿฝ๏ธ"],
116
+ ["potion", "โš—๏ธ"],
117
+ ["chem", "โš—๏ธ"],
118
+ ["heal", "๐Ÿฉน"],
119
+ ["treat", "๐Ÿฉน"],
120
+ ["poison", "โ˜ ๏ธ"],
121
+ ["radiation", "โ˜ข๏ธ"],
122
+ ["sample", "๐Ÿงช"],
123
+ ["mine", "โ›๏ธ"],
124
+ ["salvage", "๐Ÿ”ง"],
125
+ ["quest", "๐Ÿ“œ"],
126
+ ["faction", "๐Ÿณ๏ธ"],
127
+ ["crime", "โš–๏ธ"],
128
+ ["jail", "โš–๏ธ"],
129
+ ["bounty", "โš–๏ธ"],
130
+ ["attack", "โš”๏ธ"],
131
+ ["fight", "โš”๏ธ"],
132
+ ["raid", "โš”๏ธ"],
133
+ ["defeat", "โš”๏ธ"],
134
+ ["defend", "๐Ÿ›ก๏ธ"],
135
+ ["trap", "๐Ÿชค"],
136
+ ["sneak", "๐Ÿฅท"],
137
+ ["hide", "๐Ÿฅท"],
138
+ ["steal", "๐Ÿซด"],
139
+ ["spell", "โœจ"],
140
+ ["magic", "โœจ"],
141
+ ["ritual", "โœจ"],
142
+ ["dungeon", "๐Ÿ—๏ธ"],
143
+ ["map", "๐Ÿ—บ๏ธ"],
144
+ ["recall", "๐ŸŒ€"],
145
+ ["rest", "๐Ÿ’ค"],
146
+ ["sleep", "๐Ÿ’ค"],
147
+ ["ship", "๐Ÿš€"],
148
+ ["orbit", "๐Ÿช"],
149
+ ["drone", "๐Ÿ›ฐ๏ธ"],
150
+ ["ai", "๐Ÿค–"],
151
+ ["network", "๐Ÿ“ก"],
152
+ ["hack", "๐Ÿ’ป"],
153
+ ["exploit", "๐Ÿ’ป"],
154
+ ["terminal", "๐Ÿ’ป"],
155
+ ["credential", "๐Ÿชช"],
156
+ ["data", "๐Ÿ’พ"],
157
+ ["evidence", "๐Ÿงพ"],
158
+ ["camera", "๐Ÿ“ท"],
159
+ ["image", "๐Ÿ“ท"],
160
+ ["sensor", "๐Ÿ“ก"],
161
+ ["implant", "๐Ÿฆพ"],
162
+ ["call", "๐Ÿ“ฃ"],
163
+ ["signal", "๐Ÿ“ฃ"],
164
+ ["command", "๐Ÿ“ฃ"],
165
+ ["assign", "๐Ÿ“Œ"],
166
+ ["set", "๐Ÿ“Œ"],
167
+ ["configure", "โš™๏ธ"],
168
+ ["resolve", "โœ…"],
169
+ ["complete", "โœ…"],
170
+ ["accept", "โœ…"],
171
+ ["decline", "โœ‹"],
172
+ ["cancel", "๐Ÿšซ"],
173
+ ["release", "๐Ÿซณ"],
174
+ ["clean", "๐Ÿงผ"],
175
+ ["clear", "๐Ÿงน"]
176
+ ], v = /* @__PURE__ */ new Set([
177
+ "ready",
178
+ "event",
179
+ "invalidate",
180
+ "resync",
181
+ "heartbeat"
182
+ ]), ee = 2e3, te = 150, ne = 7e4, y = [
183
+ 1,
184
+ 2,
185
+ 4,
186
+ 8,
187
+ 16,
188
+ 30
189
+ ], re = 512;
190
+ function b(e) {
191
+ let t = e.webSocketFactory || (typeof globalThis.WebSocket == "function" ? (e) => new globalThis.WebSocket(e) : null);
192
+ if (!t || !e.control?.claimId) return null;
193
+ let n = `/play/claims/${encodeURIComponent(e.control.claimId)}/stream`, a = t(u(e.base, n, i()));
194
+ return a.onopen = () => {
195
+ a.send(JSON.stringify({
196
+ type: "authenticate",
197
+ data: {
198
+ token: i().startsWith("Bearer ") ? i().slice(7) : null,
199
+ claim_secret: e.control?.claimSecret || null,
200
+ client_id: e.control?.clientId || r()
201
+ }
202
+ })), e.onOpen?.();
203
+ }, a.onmessage = (t) => {
204
+ e.onAnyFrame?.();
205
+ let n;
206
+ try {
207
+ n = JSON.parse(String(t.data ?? ""));
208
+ } catch {
209
+ return;
210
+ }
211
+ if (!n || typeof n != "object") return;
212
+ let r = n;
213
+ !v.has(String(r.type)) || !r.data || typeof r.data != "object" || e.onFrame(r);
214
+ }, a.onclose = () => e.onClose?.(), a.onerror = () => e.onError?.(), a;
215
+ }
216
+ function x(e) {
217
+ let t = !1, n = "connecting", r = null, i = 0, a = 0, o = null, s = null, c = null, l = null, u = !1, d = !1, f = 0, p = /* @__PURE__ */ new Set(), m = [], h = e.random || Math.random, g = (t) => {
218
+ n !== t && (n = t, e.onState?.(t));
219
+ }, _ = () => {
220
+ c != null && clearTimeout(c), c = null;
221
+ }, v = async () => {
222
+ if (l = null, !t) {
223
+ if (u) {
224
+ d = !0;
225
+ return;
226
+ }
227
+ u = !0;
228
+ try {
229
+ await e.refresh();
230
+ } catch {} finally {
231
+ u = !1, d && !t && (d = !1, v());
232
+ }
233
+ }
234
+ }, x = (e = 0) => {
235
+ if (!t) {
236
+ if (u) {
237
+ d = !0;
238
+ return;
239
+ }
240
+ l ??= setTimeout(() => {
241
+ v();
242
+ }, e);
243
+ }
244
+ }, S = () => {
245
+ s != null && clearInterval(s), s = null;
246
+ }, C = () => {
247
+ t || s != null || (x(), s = setInterval(() => x(), ee));
248
+ }, w = (e) => {
249
+ _(), c = setTimeout(() => {
250
+ if (t || e !== i) return;
251
+ let n = r;
252
+ r = null, i += 1, n?.close(), E();
253
+ }, ne);
254
+ }, T = () => {
255
+ if (t || o != null) return;
256
+ let e = y[Math.min(a, y.length - 1)];
257
+ a += 1;
258
+ let n = e * 1e3 * (.8 + h() * .4);
259
+ o = setTimeout(() => {
260
+ o = null, D();
261
+ }, n);
262
+ }, E = () => {
263
+ t || (_(), g("fallback"), C(), T());
264
+ }, D = () => {
265
+ if (t) return;
266
+ let n = ++i;
267
+ f = 0, g("connecting"), C();
268
+ let o = b({
269
+ ...e,
270
+ onOpen: () => {
271
+ !t && n === i && w(n);
272
+ },
273
+ onAnyFrame: () => {
274
+ !t && n === i && w(n);
275
+ },
276
+ onFrame: (r) => {
277
+ if (t || n !== i) return;
278
+ let o = Number(r.stream_sequence || 0), s = o > 0 && f > 0 && o !== f + 1;
279
+ o > 0 && (f = o);
280
+ let c = typeof r.event_id == "string" ? r.event_id : "";
281
+ c && p.has(c) || (c && (p.add(c), m.push(c), m.length > re && p.delete(m.shift())), e.onFrame?.(r), r.type === "ready" ? (a = 0, S(), g("live")) : r.type === "resync" || s ? x() : r.type !== "heartbeat" && x(te));
282
+ },
283
+ onClose: () => {
284
+ t || n !== i || (r = null, E());
285
+ },
286
+ onError: () => {
287
+ if (t || n !== i) return;
288
+ let e = r;
289
+ r = null, i += 1, e?.close(), E();
290
+ }
291
+ });
292
+ if (t || n !== i) {
293
+ o?.close();
294
+ return;
295
+ }
296
+ r = o, o || E();
297
+ };
298
+ return e.onState?.(n), D(), {
299
+ close() {
300
+ if (t) return;
301
+ t = !0, i += 1, o != null && clearTimeout(o), l != null && clearTimeout(l), o = null, l = null, S(), _();
302
+ let e = r;
303
+ r = null, e?.close(), g("closed");
304
+ },
305
+ getState: () => n
306
+ };
307
+ }
308
+ function S(e = "web") {
309
+ if (typeof globalThis.crypto?.randomUUID == "function") return crypto.randomUUID();
310
+ let t = /* @__PURE__ */ new Uint8Array(16);
311
+ if (typeof globalThis.crypto?.getRandomValues == "function") {
312
+ crypto.getRandomValues(t), t[6] = t[6] & 15 | 64, t[8] = t[8] & 63 | 128;
313
+ let e = [...t].map((e) => e.toString(16).padStart(2, "0"));
314
+ return `${e.slice(0, 4).join("")}-${e.slice(4, 6).join("")}-${e.slice(6, 8).join("")}-${e.slice(8, 10).join("")}-${e.slice(10, 16).join("")}`;
315
+ }
316
+ return `${e}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
317
+ }
318
+ function C(e = "bunnyland.clientId", t = "web") {
319
+ let n = d(e);
320
+ if (n) return n;
321
+ let r = S(t);
322
+ return p(e, r), r;
323
+ }
324
+ function w(e, t) {
325
+ try {
326
+ let n = JSON.parse(d($(e, t)) || "{}");
327
+ return !n.controllerId || !n.claimId || !n.claimSecret ? null : {
328
+ characterId: t,
329
+ controllerId: String(n.controllerId),
330
+ generation: Number(n.generation || 0),
331
+ claimId: String(n.claimId),
332
+ claimSecret: String(n.claimSecret),
333
+ clientId: String(n.clientId || r()),
334
+ active: n.active !== !1
335
+ };
336
+ } catch {
337
+ return null;
338
+ }
339
+ }
340
+ function T(e, t) {
341
+ !e || !t.characterId || !t.claimId || !t.claimSecret || p($(e, t.characterId), JSON.stringify({
342
+ controllerId: t.controllerId,
343
+ generation: t.generation,
344
+ claimId: t.claimId,
345
+ claimSecret: t.claimSecret,
346
+ clientId: t.clientId,
347
+ active: t.active !== !1
348
+ }));
349
+ }
350
+ function E(e, t) {
351
+ f($(e, t));
352
+ }
353
+ function D(t) {
354
+ return t instanceof e && t.status === 404;
355
+ }
356
+ var O = /* @__PURE__ */ new Map();
357
+ async function ie(e, r) {
358
+ let i = t(e), a = `${i}\0${r.claimId}\0${r.claimSecret}`, o = O.get(a);
359
+ if (o) return o;
360
+ let s = c(i, `/play/claims/${encodeURIComponent(r.claimId)}/projection`, { headers: n(r) });
361
+ O.set(a, s);
362
+ try {
363
+ return await s;
364
+ } finally {
365
+ O.get(a) === s && O.delete(a);
366
+ }
367
+ }
368
+ async function k(e, t, n = null) {
369
+ if (!n?.claimId) return {
370
+ character: null,
371
+ queued: null
372
+ };
373
+ let r = await ie(e, n);
374
+ return {
375
+ character: M(r),
376
+ queued: N(r)
377
+ };
378
+ }
379
+ async function ae(e) {
380
+ return j(await c(e, "/play/characters")).characters;
381
+ }
382
+ async function A(e, r, i, a = {}) {
383
+ let c = w(i, r), u = C(a.clientIdKey || `${i}.clientId`, a.clientIdPrefix || "web");
384
+ l(u);
385
+ let d = o(n({
386
+ ...c,
387
+ clientId: u
388
+ })), f = c?.claimId ? `/play/claims/${encodeURIComponent(c.claimId)}` : "/play/claims", p, m;
389
+ try {
390
+ p = await fetch(`${t(e)}${f}`, {
391
+ method: c?.claimId ? "PUT" : "POST",
392
+ headers: d,
393
+ credentials: "include",
394
+ ...c?.claimId ? {} : { body: JSON.stringify({
395
+ character_id: r,
396
+ fallback_controller: a.fallbackController || "suspend",
397
+ timeout_seconds: a.timeoutSeconds || 1800,
398
+ label: a.label || "web"
399
+ }) }
400
+ }), m = await s(p);
401
+ } catch (t) {
402
+ if (!c?.claimId || !D(t)) throw t;
403
+ return E(i, r), A(e, r, i, a);
404
+ }
405
+ let h = p.headers.get("X-Bunnyland-Claim-Secret") || c?.claimSecret || "", g = P({
406
+ ...m,
407
+ claim_secret: h,
408
+ client_id: u
409
+ }, r, { active: m.control !== "fallback" });
410
+ return T(i, g), g;
411
+ }
412
+ async function oe(e, t, n = null) {
413
+ return (await k(e, t, n)).character;
414
+ }
415
+ async function se(e, t, n = null) {
416
+ return (await k(e, t, n)).queued;
417
+ }
418
+ async function ce(e, t, r = null) {
419
+ if (!r?.claimId) throw Error("A character claim is required");
420
+ let i = t, a = {
421
+ command_type: i.command_type,
422
+ payload: i.payload || {},
423
+ cost: i.cost || {},
424
+ lane: i.lane || "world",
425
+ on_insufficient_points: i.on_insufficient_points || "queue",
426
+ expires_at_epoch: i.expires_at_epoch,
427
+ expected_epoch: i.expected_epoch,
428
+ id: i.command_id
429
+ };
430
+ return c(e, `/play/claims/${encodeURIComponent(r.claimId)}/commands`, {
431
+ method: "POST",
432
+ headers: n(r),
433
+ body: JSON.stringify(a)
434
+ });
435
+ }
436
+ async function le(e, t, r, i) {
437
+ return c(e, `/play/claims/${encodeURIComponent(i.claimId)}/commands/${encodeURIComponent(r)}`, {
438
+ method: "DELETE",
439
+ headers: n(i)
440
+ });
441
+ }
442
+ async function ue(e) {
443
+ let t = await c(e, "/admin/world/events");
444
+ return Array.isArray(t.events) ? t.events : [];
445
+ }
446
+ async function de(e, t, r = null) {
447
+ if (!r?.claimId) return [];
448
+ let i = await c(e, `/play/claims/${encodeURIComponent(r.claimId)}/events`, { headers: n(r) });
449
+ return Array.isArray(i.events) ? i.events : [];
450
+ }
451
+ function j(e) {
452
+ let t = e;
453
+ return {
454
+ epoch: Number(t?.world_epoch || 0),
455
+ characters: (t?.characters || []).map((e) => {
456
+ let t = e;
457
+ return {
458
+ id: String(t.id || t.character_id || ""),
459
+ name: String(t.name || t.id || t.character_id || ""),
460
+ kind: String(t.kind || "character"),
461
+ suspended: !!t.suspended
462
+ };
463
+ }).filter((e) => e.id)
464
+ };
465
+ }
466
+ function M(e) {
467
+ let t = e, n = t?.character || t;
468
+ if (!n || !n.character_id) return null;
469
+ let r = (t?.scene || {}).room || n.room || {}, i = {};
470
+ for (let [e, t] of Object.entries(n.target_groups || {})) i[e] = (t || []).map((t) => {
471
+ let n = t;
472
+ return {
473
+ value: String(n.id || ""),
474
+ label: String(n.label || n.id || ""),
475
+ kind: String(n.kind || e),
476
+ icon: Q(String(n.kind || e))
477
+ };
478
+ }).filter((e) => e.value);
479
+ return {
480
+ characterId: String(n.character_id || ""),
481
+ characterName: String(n.character_name || n.character_id || ""),
482
+ worldEpoch: Number(t?.world_epoch || n.world_epoch || 0),
483
+ room: {
484
+ id: String(r.id || ""),
485
+ title: String(r.title || r.id || ""),
486
+ biome: String(r.biome || "unknown"),
487
+ exits: (r.exits || []).map((e) => {
488
+ let t = e;
489
+ return {
490
+ id: String(t.id || ""),
491
+ direction: String(t.direction || ""),
492
+ label: String(t.label || t.id || ""),
493
+ locked: !!t.locked
494
+ };
495
+ }).filter((e) => e.id),
496
+ entities: Array.isArray(r.entities) ? r.entities : []
497
+ },
498
+ inventory: Array.isArray(n.inventory) ? n.inventory : [],
499
+ points: n.points || {},
500
+ controller: n.controller || null,
501
+ portrait: n.portrait || {},
502
+ sheet: t?.sheet || n.sheet || {},
503
+ targetGroups: i,
504
+ actions: Array.isArray(t?.actions) ? t.actions : Array.isArray(n.actions) ? n.actions : []
505
+ };
506
+ }
507
+ function N(e) {
508
+ let t = e, n = t?.character || t;
509
+ return !n || !n.character_id ? null : {
510
+ characterId: String(n.character_id || ""),
511
+ worldEpoch: Number(t?.world_epoch || n.world_epoch || 0),
512
+ generatedAtUnix: n.generated_at_unix == null ? null : Number(n.generated_at_unix),
513
+ nextTickAtUnix: n.next_tick_at_unix == null ? null : Number(n.next_tick_at_unix),
514
+ tickSeconds: n.tick_seconds == null ? null : Number(n.tick_seconds),
515
+ commands: Array.isArray(t?.commands) ? t.commands : Array.isArray(n.commands) ? n.commands : []
516
+ };
517
+ }
518
+ function P(e, t = "", { active: n = !0 } = {}) {
519
+ let i = e;
520
+ return i ? {
521
+ characterId: String(i.character_id || t),
522
+ controllerId: String(i.controller_id || ""),
523
+ generation: Number(i.controller_generation ?? i.generation ?? 0),
524
+ claimId: String(i.id || i.claim_id || ""),
525
+ claimSecret: String(i.claim_secret || ""),
526
+ clientId: String(i.client_id || r()),
527
+ active: n
528
+ } : null;
529
+ }
530
+ function F(e) {
531
+ return String(e.title || e.tool_name || e.command_type || "Action");
532
+ }
533
+ function I(e) {
534
+ if (e.icon) return String(e.icon);
535
+ let t = R(e).trim().toLowerCase().replaceAll("_", "-");
536
+ if (g[t]) return g[t];
537
+ let n = t.split("-"), r = _.find(([e]) => n.includes(e));
538
+ return r ? r[1] : "โ€ข";
539
+ }
540
+ function L(e) {
541
+ return String(e.tool_name || e.command_type || "action");
542
+ }
543
+ function R(e) {
544
+ return String(e.command_type || ("tool_name" in e ? e.tool_name : "") || "action");
545
+ }
546
+ function fe(e) {
547
+ let t = e.cost || {};
548
+ return {
549
+ action: Number(t.action || 0),
550
+ focus: Number(t.focus || 0)
551
+ };
552
+ }
553
+ function pe(e) {
554
+ return String(e.lane || "world");
555
+ }
556
+ function z(e) {
557
+ return Array.isArray(e.arguments) ? e.arguments : [];
558
+ }
559
+ function B(e) {
560
+ return e.available !== !1;
561
+ }
562
+ function V(e) {
563
+ return B(e) ? "" : String(e.unavailable_reason || "Unavailable right now");
564
+ }
565
+ function H(e) {
566
+ return (e || []).map((e, t) => ({
567
+ action: e,
568
+ index: t
569
+ })).sort((e, t) => !B(e.action) - +!B(t.action) || e.index - t.index).map((e) => e.action);
570
+ }
571
+ function me(e, t = "") {
572
+ let n = String(t || "").trim().toLowerCase();
573
+ return H(n ? (e || []).filter((e) => F(e).toLowerCase().includes(n) || L(e).toLowerCase().includes(n) || R(e).toLowerCase().includes(n) || V(e).toLowerCase().includes(n)) : e || []);
574
+ }
575
+ function he(e, t) {
576
+ return z(e).filter((e) => e.key && (e.required || e.target_group)).map((e) => ({
577
+ key: e.key,
578
+ label: e.title || e.key,
579
+ kind: e.kind || "string",
580
+ required: !!e.required,
581
+ candidates: e.target_group ? t.targetGroups[e.target_group] || [] : null
582
+ }));
583
+ }
584
+ function ge(e) {
585
+ let t = [], n = /* @__PURE__ */ new Set(), r = (e, r, i = "") => {
586
+ let a = String(e || "");
587
+ if (!a || n.has(a)) return;
588
+ n.add(a);
589
+ let o = String(i || "other");
590
+ t.push({
591
+ value: a,
592
+ label: String(r || a),
593
+ kind: o,
594
+ icon: Q(o)
595
+ });
596
+ };
597
+ for (let t of Object.values(e?.targetGroups || {})) for (let e of t || []) r(e.value, e.label, e.kind);
598
+ for (let t of e?.room.entities || []) {
599
+ let e = t;
600
+ r(e.id, e.name || e.label || e.id, String(e.kind || (e.is_character ? "character" : "other")));
601
+ }
602
+ for (let t of e?.room.exits || []) r(t.id, t.direction || t.label || t.id, "exit");
603
+ for (let t of e?.inventory || []) r(t.id, t.label || t.name || t.id, t.kind || "item");
604
+ return t;
605
+ }
606
+ function _e(e) {
607
+ return (e?.inventory || []).map((e) => ({
608
+ value: e.id,
609
+ label: e.label || e.name || e.id,
610
+ kind: e.kind || "item",
611
+ icon: Q(e.kind || "item")
612
+ })).filter((e) => e.value);
613
+ }
614
+ function ve(e, t = !0) {
615
+ let n = d(e);
616
+ return n == null ? t : n !== "false";
617
+ }
618
+ function ye(e, t) {
619
+ p(e, t ? "true" : "false");
620
+ }
621
+ function be(e) {
622
+ let t = e?.nextTickAtUnix;
623
+ return t == null ? null : Math.max(0, Math.round(Number(t) - Date.now() / 1e3));
624
+ }
625
+ function U(e) {
626
+ let t = e.cost || {}, n = [];
627
+ return t.action && n.push(`${t.action} AP`), t.focus && n.push(`${t.focus} FP`), n.length ? n.join(" + ") : "free";
628
+ }
629
+ function W(e) {
630
+ return Object.entries(e.payload || {}).filter(([, e]) => e != null && e !== "").map(([e, t]) => `${e}: ${String(t)}`).join(", ");
631
+ }
632
+ function G(e, t = []) {
633
+ let n = t.find((t) => t.command_type === e.command_type);
634
+ return n ? F(n) : String(e.command_type || "command").replaceAll("-", " ");
635
+ }
636
+ function xe(e, t = []) {
637
+ let n = G(e, t), r = e.lane ? ` [${e.lane}]` : "", i = [U(e), W(e)].filter(Boolean);
638
+ return `${n}${r}${i.length ? ` - ${i.join(" ยท ")}` : ""}`;
639
+ }
640
+ function Se(e) {
641
+ let t = e;
642
+ return !t || t.ok === !1 ? `${m.REQUEST_EMOJI} ${String(t?.reason || "image request failed")}` : t.status === "skipped" ? `${m.DELIVER_EMOJI} image ready` : `${m.ACK_EMOJI} image requested`;
643
+ }
644
+ function K(e, t = "") {
645
+ let n = Z(e);
646
+ if (n.event_type !== "ImageGenerationCompletedEvent") return null;
647
+ let r = n.event || {};
648
+ return r.url ? {
649
+ entityId: String(r.entity_id || ""),
650
+ purpose: String(r.purpose || ""),
651
+ url: a(t, String(r.url)),
652
+ alphaUrl: r.alpha_url ? a(t, String(r.alpha_url)) : "",
653
+ epoch: Number(r.world_epoch || 0)
654
+ } : null;
655
+ }
656
+ function q(e, t = "", n = "") {
657
+ return (e || []).map((e) => K(e, t)).filter((e) => e ? !n || e.purpose === n : !1).sort((e, t) => e.epoch - t.epoch);
658
+ }
659
+ function Ce(e, t = "", n = "") {
660
+ let r = typeof t == "string" ? {
661
+ base: t,
662
+ purpose: n
663
+ } : t, i = null;
664
+ for (let t of q(e, r.base || "", r.purpose || "")) (!i || t.epoch >= i.epoch) && (i = t);
665
+ return i;
666
+ }
667
+ function J(e) {
668
+ let t = Z(e);
669
+ if (t.event_type !== "ImageGenerationFailedEvent") return null;
670
+ let n = t.event || {};
671
+ return {
672
+ entityId: String(n.entity_id || ""),
673
+ purpose: String(n.purpose || ""),
674
+ reason: String(n.reason || "image generation failed"),
675
+ epoch: Number(n.world_epoch || 0)
676
+ };
677
+ }
678
+ function we(e, t = "") {
679
+ let n = typeof t == "string" ? t : t.purpose || "", r = null;
680
+ for (let t of e || []) {
681
+ let e = J(t);
682
+ !e || n && e.purpose !== n || (!r || e.epoch >= r.epoch) && (r = e);
683
+ }
684
+ return r;
685
+ }
686
+ function Te(e, n, r = "sheet", i = "character.html") {
687
+ let a = new URL(i, location.href);
688
+ if (a.origin !== location.origin) throw Error("Bunnyland browser links must use the page origin");
689
+ let o = t(e);
690
+ return o ? a.searchParams.set("server", o) : a.searchParams.delete("server"), r === "chat" ? a.searchParams.set("view", "chat") : a.searchParams.delete("view"), a.hash = n || "", `${a.pathname.split("/").pop()}${a.search}${a.hash}`;
691
+ }
692
+ function Ee(e, t = "") {
693
+ return e?.portrait?.url ? "Portrait ready." : t === "requesting" ? "Requesting portrait..." : t === "queued" ? "Portrait generation queued." : t === "failed" ? "Portrait generation unavailable." : "Portrait pending.";
694
+ }
695
+ function De(e, { seenIds: t = /* @__PURE__ */ new Set(), playerId: n = "", roomOf: r = () => null, nameFor: i = () => null } = {}) {
696
+ let a = new Set(t), o = [];
697
+ for (let s of e || []) {
698
+ let e = Z(s), c = e.event || {}, l = String(c.event_id || "");
699
+ if (!l || (a.add(l), t.has(l))) continue;
700
+ let u = String(e.event_type || "Event");
701
+ Oe.has(u) || (n && c.actor_id === n || Ne(c, {
702
+ playerId: n,
703
+ roomOf: r
704
+ })) && o.push(je(e, {
705
+ playerId: n,
706
+ nameFor: i
707
+ }));
708
+ }
709
+ return {
710
+ lines: o,
711
+ seenIds: a
712
+ };
713
+ }
714
+ var Oe = /* @__PURE__ */ new Set([
715
+ "CommandSubmittedEvent",
716
+ "CommandAcceptedEvent",
717
+ "CommandQueuedEvent",
718
+ "CommandCancelledEvent",
719
+ "CommandExecutedEvent",
720
+ "CommandExpiredEvent",
721
+ "ActionPointsChangedEvent",
722
+ "FocusPointsChangedEvent",
723
+ "EncumbranceChangedEvent",
724
+ "PainChangedEvent",
725
+ "BleedingChangedEvent",
726
+ "AttentionShiftedEvent",
727
+ "AffectChangedEvent",
728
+ "EntitySeenEvent",
729
+ "RoomQualityUpdatedEvent",
730
+ "HungerChangedEvent",
731
+ "ThirstChangedEvent",
732
+ "DailyNeedChangedEvent",
733
+ "SkillXPChangedEvent"
734
+ ]), Y = /* @__PURE__ */ new Set(["ControllerChangedEvent", "WorldPauseStatusChangedEvent"]), ke = {
735
+ ActorMovedEvent: "โžก๏ธ",
736
+ RoomLookedEvent: "๐Ÿ‘๏ธ",
737
+ CommandRejectedEvent: "โš ๏ธ",
738
+ ControllerChangedEvent: "๐ŸŽฎ",
739
+ WorldPauseStatusChangedEvent: "โธ๏ธ",
740
+ CharacterClaimedEvent: "๐ŸŽฎ"
741
+ }, Ae = /* @__PURE__ */ new Set([
742
+ "event_id",
743
+ "world_epoch",
744
+ "created_at",
745
+ "visibility",
746
+ "actor_id",
747
+ "room_id",
748
+ "target_ids",
749
+ "causation_id",
750
+ "correlation_id",
751
+ "arrival_summary"
752
+ ]);
753
+ function je(e, { playerId: t = "", nameFor: n = () => null } = {}) {
754
+ let r = e.event || {}, i = String(e.event_type || "Event");
755
+ if (i === "ActorMovedEvent" && t && r.actor_id === t && r.arrival_summary) return {
756
+ text: String(r.arrival_summary),
757
+ kind: "event",
758
+ icon: X(i, r)
759
+ };
760
+ if (i === "RoomLookedEvent" && r.summary) return {
761
+ text: String(r.summary),
762
+ kind: "event",
763
+ icon: X(i, r)
764
+ };
765
+ let a = r.actor_id ? n(String(r.actor_id)) : null, o = [];
766
+ for (let [e, t] of Object.entries(r)) if (!(Ae.has(e) || t == null || t === "" || Array.isArray(t) && !t.length)) if (e.endsWith("_ids") && Array.isArray(t)) {
767
+ let e = t.map((e) => n(String(e))).filter(Boolean);
768
+ e.length && o.push(e.join(", "));
769
+ } else if (e.endsWith("_id")) {
770
+ let e = n(String(t));
771
+ e && o.push(e);
772
+ } else e === "facts" && Array.isArray(t) ? o.push(...t.flatMap((e) => {
773
+ if (!e || typeof e != "object" || !("text" in e)) return [];
774
+ let t = String(e.text || "").trim();
775
+ return t ? [t] : [];
776
+ })) : o.push(`${e.replaceAll("_", " ")} ${String(t)}`);
777
+ return {
778
+ text: `${a ? `${a}: ` : ""}${Me(i)}${o.length ? ` - ${o.join("; ")}` : ""}`,
779
+ kind: i === "CommandRejectedEvent" ? "rejection" : Y.has(i) ? "system" : "event",
780
+ icon: X(i, r)
781
+ };
782
+ }
783
+ function X(e, t = {}) {
784
+ return e === "CommandRejectedEvent" && t.command_type ? I({ command_type: String(t.command_type) }) : ke[e] || "โ€ข";
785
+ }
786
+ function Me(e) {
787
+ return String(e || "Event").replace(/Event$/, "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase());
788
+ }
789
+ function Ne(e, { playerId: t = "", roomOf: n = () => null } = {}) {
790
+ let r = e.visibility;
791
+ return r === "public" ? !0 : r === "room" ? !!t && e.room_id === n(t) : r === "directed" ? !!t && (e.actor_id === t || (e.target_ids || []).includes(t)) : r === "private" && !!t && e.actor_id === t;
792
+ }
793
+ function Z(e) {
794
+ let t = e;
795
+ return t?.data || t || {};
796
+ }
797
+ function Q(e) {
798
+ return e === "exit" ? h.door : e === "object" ? h.other : h[e] || h.other;
799
+ }
800
+ function $(e, t) {
801
+ return `${e}.claim.${t}`;
802
+ }
803
+ //#endregion
804
+ export { m as IMAGE_AFFORDANCE, h as KIND_ICON, z as actionArguments, B as actionAvailable, R as actionCommandType, fe as actionCost, he as actionFields, I as actionIcon, pe as actionLane, F as actionTitle, L as actionTool, V as actionUnavailableReason, ge as allTargets, le as cancelQueuedCommand, Te as characterHref, A as claimCharacter, E as clearClaimControl, P as controlFromResponse, x as createPlayerLiveUpdates, De as drainNarratedEvents, oe as fetchCharacterProjection, de as fetchCharacterRecentEvents, ae as fetchCharacters, k as fetchClaimProjection, se as fetchQueuedCommands, ue as fetchRecentEvents, me as filterActions, ve as iconPreference, K as imageCompletionFromMessage, q as imageCompletions, J as imageFailureFromMessage, Se as imageRequestMessage, _e as inventoryEntries, D as isClaimNotFoundError, Ce as latestImageCompletion, we as latestImageFailure, b as openPlayerUpdates, H as orderActionsByAvailability, j as parseCharacterList, M as parseCharacterProjection, N as parseQueuedCommands, C as persistentClientId, Ee as portraitStatusMessage, U as queuedCommandCost, W as queuedCommandDetail, xe as queuedCommandLabel, G as queuedCommandName, be as queuedCountdownSeconds, S as randomClientId, ye as setIconPreference, T as storeClaimControl, w as storedClaimControl, ce as submitCommand };
805
+
806
+ //# sourceMappingURL=play.js.map