@vibes.diy/vibe-srv-sandbox 2.5.10 → 2.5.11-dev.1

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.
package/srv-sandbox.js CHANGED
@@ -1,8 +1,9 @@
1
- import { Evento, Lazy, Result, Option, EventoResult, processStream, exception2Result, Future, OnFunc, } from "@adviser/cement";
2
- import { isReqCallAI, isEvtRuntimeReady, isReqImgGen, isReqPutDoc, isReqGetDoc, isReqQueryDocs, isReqDeleteDoc, isReqSetDbAcl, isReqSubscribeDocs, isReqListDbNames, isEvtVibeHotSwapError, isReqVibePutAsset, isReqVibeWhoAmI, isReqVibeUpdateAvatarCid, isReqVibeLogin, isReqOpenDmThread, } from "@vibes.diy/vibe-types";
3
- import { isPromptBlockEnd, isPromptReq, isSectionEvent } from "@vibes.diy/api-types";
4
- import { isBlockImage, isCodeBegin, isCodeEnd, isCodeLine } from "@vibes.diy/call-ai-v2";
5
- import { buildSchemaSystemMessage } from "@vibes.diy/prompts";
1
+ import { Evento, Lazy, Result, Option, EventoResult, OnFunc, } from "@adviser/cement";
2
+ import { isEvtRuntimeReady, isEvtVibeHotSwapError, isReqOpenDmThread, } from "@vibes.diy/vibe-types";
3
+ import { vibeCallAI, vibeImgGen } from "./srv-sandbox-ai-image-handlers.js";
4
+ import { vibePutDoc, vibeGetDoc, vibeQueryDocs, vibeDeleteDoc, vibeSubscribeDocs, vibeSetDbAcl, vibeListDbNames, } from "./srv-sandbox-firefly-doc-handlers.js";
5
+ import { vibePutAsset, vibeWhoAmI, vibeUpdateAvatarCid, vibeRequestLogin } from "./srv-sandbox-asset-identity-auth-handlers.js";
6
+ export { getCodeBlock, getImageFiles } from "./srv-sandbox-ai-image-handlers.js";
6
7
  export class MessageEventEventoEnDecoder {
7
8
  async encode(me) {
8
9
  return Result.Ok(me);
@@ -39,674 +40,6 @@ function vibeRuntimeReady(sandbox) {
39
40
  },
40
41
  };
41
42
  }
42
- export function getCodeBlock(stream) {
43
- const codeParts = [];
44
- let promptReq;
45
- const firstCodeBlock = new Future();
46
- processStream(stream, (msg) => {
47
- if (isSectionEvent(msg)) {
48
- for (const block of msg.blocks) {
49
- if (isPromptReq(block)) {
50
- promptReq = block;
51
- }
52
- if (isCodeBegin(block) && block.lang.toLocaleUpperCase() === "JSON") {
53
- codeParts.splice(0, codeParts.length);
54
- }
55
- if (isCodeLine(block)) {
56
- codeParts.push(block.line);
57
- }
58
- if (isCodeEnd(block)) {
59
- firstCodeBlock.resolve({ code: codeParts.join("\n"), sectionEvt: msg, promptReq, codeEnd: block });
60
- }
61
- }
62
- }
63
- });
64
- return firstCodeBlock.asPromise();
65
- }
66
- function vibeCallAI(sandbox) {
67
- const { chatApi } = sandbox.args;
68
- return {
69
- hash: "vibe.callAI",
70
- validate: (ctx) => {
71
- const { request: req } = ctx;
72
- if (isReqCallAI(req?.data)) {
73
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
74
- }
75
- return Promise.resolve(Result.Ok(Option.None()));
76
- },
77
- handle: async (ctx) => {
78
- await chatApi
79
- .openChat({ ownerHandle: ctx.validated.ownerHandle, appSlug: ctx.validated.appSlug, mode: "app" })
80
- .then(async (rChat) => {
81
- if (rChat.isErr()) {
82
- return ctx.send.send(ctx, {
83
- tid: ctx.validated.tid,
84
- type: "vibe.res.callAI",
85
- status: "error",
86
- message: rChat.Err().message,
87
- });
88
- }
89
- getCodeBlock(rChat.Ok().sectionStream)
90
- .then(({ code, sectionEvt: msg }) => {
91
- ctx.send.send(ctx, {
92
- tid: ctx.validated.tid,
93
- type: "vibe.res.callAI",
94
- status: "ok",
95
- promptId: msg.promptId,
96
- result: code,
97
- });
98
- })
99
- .catch((err) => {
100
- ctx.send.send(ctx, {
101
- tid: ctx.validated.tid,
102
- type: "vibe.res.callAI",
103
- status: "error",
104
- message: err?.message ?? String(err),
105
- });
106
- });
107
- const generateSchema = [];
108
- if (ctx.validated.schema) {
109
- generateSchema.push({
110
- role: "system",
111
- content: [
112
- {
113
- type: "text",
114
- text: await buildSchemaSystemMessage(ctx.validated.schema),
115
- },
116
- ],
117
- });
118
- }
119
- const rPrompt = await rChat.Ok().prompt({
120
- messages: [
121
- ...generateSchema,
122
- {
123
- role: "user",
124
- content: [
125
- {
126
- type: "text",
127
- text: ctx.validated.prompt,
128
- },
129
- ],
130
- },
131
- ],
132
- });
133
- if (rPrompt.isErr()) {
134
- return ctx.send.send(ctx, {
135
- tid: ctx.validated.tid,
136
- type: "vibe.res.callAI",
137
- status: "error",
138
- message: rPrompt.Err().message,
139
- });
140
- }
141
- });
142
- return Result.Ok(EventoResult.Stop);
143
- },
144
- };
145
- }
146
- export function getImageFiles(stream) {
147
- const files = [];
148
- const done = new Future();
149
- processStream(stream, (msg) => {
150
- if (isSectionEvent(msg)) {
151
- for (const block of msg.blocks) {
152
- if (isBlockImage(block)) {
153
- if (block.uploadId && block.cid && block.mimeType && typeof block.size === "number") {
154
- files.push({ uploadId: block.uploadId, cid: block.cid, mimeType: block.mimeType, size: block.size });
155
- }
156
- }
157
- if (isPromptBlockEnd(block)) {
158
- done.resolve(files);
159
- }
160
- }
161
- }
162
- });
163
- return done.asPromise();
164
- }
165
- function vibeImgGen(sandbox) {
166
- return {
167
- hash: "vibe.imgGen",
168
- validate: (ctx) => {
169
- const { request: req } = ctx;
170
- if (isReqImgGen(req?.data)) {
171
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
172
- }
173
- return Promise.resolve(Result.Ok(Option.None()));
174
- },
175
- handle: async (ctx) => {
176
- const tid = ctx.validated.tid;
177
- const sendErr = (message) => ctx.send.send(ctx, {
178
- tid,
179
- type: "vibe.res.imgGen",
180
- status: "error",
181
- message,
182
- });
183
- const sendOk = (files) => ctx.send.send(ctx, {
184
- tid,
185
- type: "vibe.res.imgGen",
186
- status: "ok",
187
- files,
188
- });
189
- const api = await requireVibeApi(sandbox, ctx, "vibe.res.imgGen");
190
- if (api === undefined)
191
- return Result.Ok(EventoResult.Stop);
192
- await api
193
- .openChat({ ownerHandle: ctx.validated.ownerHandle, appSlug: ctx.validated.appSlug, mode: "img" })
194
- .then(async (rChat) => {
195
- if (rChat.isErr())
196
- return sendErr(rChat.Err().message);
197
- const chat = rChat.Ok();
198
- const filesPromise = getImageFiles(chat.sectionStream);
199
- const rPrompt = await chat.prompt({
200
- ...(ctx.validated.model ? { model: ctx.validated.model } : {}),
201
- messages: [{ role: "user", content: [{ type: "text", text: ctx.validated.prompt }] }],
202
- }, ctx.validated.inputImageBase64 ? { inputImageBase64: ctx.validated.inputImageBase64 } : undefined);
203
- if (rPrompt.isErr())
204
- return sendErr(rPrompt.Err().message);
205
- const rFiles = await exception2Result(() => filesPromise);
206
- if (rFiles.isErr())
207
- return sendErr(rFiles.Err().message);
208
- const files = rFiles.Ok();
209
- if (!files || files.length === 0) {
210
- return sendErr("Image generation completed without producing a file");
211
- }
212
- return sendOk(files);
213
- });
214
- return Result.Ok(EventoResult.Stop);
215
- },
216
- };
217
- }
218
- async function requireVibeApi(sandbox, ctx, resType) {
219
- const vibeApi = sandbox.vibeApi;
220
- if (vibeApi !== undefined)
221
- return vibeApi;
222
- const { ownerHandle, appSlug } = ctx.validated;
223
- const where = ownerHandle !== undefined && appSlug !== undefined ? ` for ${ownerHandle}/${appSlug}` : "";
224
- await ctx.send.send(ctx, {
225
- tid: ctx.validated.tid,
226
- type: resType,
227
- status: "error",
228
- message: `vibeApi unavailable — no active app session for this route${where} (route not vibe-bound yet or provider/session mismatch)`,
229
- });
230
- return undefined;
231
- }
232
- function vibePutDoc(sandbox) {
233
- return {
234
- hash: "vibe.putDoc",
235
- validate: (ctx) => {
236
- const { request: req } = ctx;
237
- if (isReqPutDoc(req?.data)) {
238
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
239
- }
240
- return Promise.resolve(Result.Ok(Option.None()));
241
- },
242
- handle: async (ctx) => {
243
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-put-doc");
244
- if (api === undefined)
245
- return Result.Ok(EventoResult.Stop);
246
- const rRes = await api.putDoc({
247
- ownerHandle: ctx.validated.ownerHandle,
248
- appSlug: ctx.validated.appSlug,
249
- dbName: ctx.validated.dbName,
250
- doc: ctx.validated.doc,
251
- docId: ctx.validated.docId,
252
- });
253
- if (rRes.isErr()) {
254
- const err = rRes.Err();
255
- const errMessage = typeof err === "string" ? err : (err?.message ?? "unknown error");
256
- const code = typeof err === "string" ? undefined : err?.error?.code;
257
- const isAccessDenied = code === "access-denied" || errMessage === "Access denied";
258
- let toast;
259
- if (code === "access-denied") {
260
- const trimmed = errMessage.trim();
261
- toast = trimmed.length > 200 ? `${trimmed.slice(0, 199)}…` : trimmed;
262
- }
263
- else if (errMessage === "Access denied") {
264
- toast = "You have read-only access to this app.";
265
- }
266
- else {
267
- toast = "Failed to save your changes. Please try again.";
268
- }
269
- sandbox.args.errorLogger(toast);
270
- if (!isAccessDenied) {
271
- console.debug("vibePutDoc failed", err);
272
- }
273
- await ctx.send.send(ctx, {
274
- tid: ctx.validated.tid,
275
- type: "vibes.diy.res-put-doc",
276
- status: "error",
277
- message: errMessage,
278
- });
279
- }
280
- else {
281
- const res = rRes.Ok();
282
- await ctx.send.send(ctx, {
283
- tid: ctx.validated.tid,
284
- type: "vibes.diy.res-put-doc",
285
- status: "ok",
286
- id: res.id,
287
- });
288
- }
289
- return Result.Ok(EventoResult.Stop);
290
- },
291
- };
292
- }
293
- function vibeGetDoc(sandbox) {
294
- return {
295
- hash: "vibe.getDoc",
296
- validate: (ctx) => {
297
- const { request: req } = ctx;
298
- if (isReqGetDoc(req?.data)) {
299
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
300
- }
301
- return Promise.resolve(Result.Ok(Option.None()));
302
- },
303
- handle: async (ctx) => {
304
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-get-doc");
305
- if (api === undefined)
306
- return Result.Ok(EventoResult.Stop);
307
- const rRes = await api.getDoc({
308
- ownerHandle: ctx.validated.ownerHandle,
309
- appSlug: ctx.validated.appSlug,
310
- dbName: ctx.validated.dbName,
311
- docId: ctx.validated.docId,
312
- });
313
- if (rRes.isErr()) {
314
- await ctx.send.send(ctx, {
315
- tid: ctx.validated.tid,
316
- type: "vibes.diy.res-get-doc",
317
- status: "error",
318
- message: rRes.Err().message,
319
- });
320
- }
321
- else {
322
- const res = rRes.Ok();
323
- await ctx.send.send(ctx, {
324
- ...res,
325
- tid: ctx.validated.tid,
326
- type: "vibes.diy.res-get-doc",
327
- });
328
- }
329
- return Result.Ok(EventoResult.Stop);
330
- },
331
- };
332
- }
333
- function vibeQueryDocs(sandbox) {
334
- return {
335
- hash: "vibe.queryDocs",
336
- validate: (ctx) => {
337
- const { request: req } = ctx;
338
- if (isReqQueryDocs(req?.data)) {
339
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
340
- }
341
- return Promise.resolve(Result.Ok(Option.None()));
342
- },
343
- handle: async (ctx) => {
344
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-query-docs");
345
- if (api === undefined)
346
- return Result.Ok(EventoResult.Stop);
347
- const rRes = await api.queryDocs({
348
- ownerHandle: ctx.validated.ownerHandle,
349
- appSlug: ctx.validated.appSlug,
350
- dbName: ctx.validated.dbName,
351
- });
352
- if (rRes.isErr()) {
353
- await ctx.send.send(ctx, {
354
- tid: ctx.validated.tid,
355
- type: "vibes.diy.res-query-docs",
356
- status: "error",
357
- message: rRes.Err().message,
358
- });
359
- }
360
- else {
361
- const res = rRes.Ok();
362
- await ctx.send.send(ctx, {
363
- ...res,
364
- tid: ctx.validated.tid,
365
- type: "vibes.diy.res-query-docs",
366
- });
367
- }
368
- return Result.Ok(EventoResult.Stop);
369
- },
370
- };
371
- }
372
- function vibeDeleteDoc(sandbox) {
373
- return {
374
- hash: "vibe.deleteDoc",
375
- validate: (ctx) => {
376
- const { request: req } = ctx;
377
- if (isReqDeleteDoc(req?.data)) {
378
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
379
- }
380
- return Promise.resolve(Result.Ok(Option.None()));
381
- },
382
- handle: async (ctx) => {
383
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-delete-doc");
384
- if (api === undefined)
385
- return Result.Ok(EventoResult.Stop);
386
- const rRes = await api.deleteDoc({
387
- ownerHandle: ctx.validated.ownerHandle,
388
- appSlug: ctx.validated.appSlug,
389
- dbName: ctx.validated.dbName,
390
- docId: ctx.validated.docId,
391
- });
392
- if (rRes.isErr()) {
393
- await ctx.send.send(ctx, {
394
- tid: ctx.validated.tid,
395
- type: "vibes.diy.res-delete-doc",
396
- status: "error",
397
- message: rRes.Err().message,
398
- });
399
- }
400
- else {
401
- const res = rRes.Ok();
402
- await ctx.send.send(ctx, {
403
- ...res,
404
- tid: ctx.validated.tid,
405
- type: "vibes.diy.res-delete-doc",
406
- });
407
- }
408
- return Result.Ok(EventoResult.Stop);
409
- },
410
- };
411
- }
412
- function vibeSubscribeDocs(sandbox) {
413
- return {
414
- hash: "vibe.subscribeDocs",
415
- validate: (ctx) => {
416
- const { request: req } = ctx;
417
- if (isReqSubscribeDocs(req?.data)) {
418
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
419
- }
420
- return Promise.resolve(Result.Ok(Option.None()));
421
- },
422
- handle: async (ctx) => {
423
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-subscribe-docs");
424
- if (api === undefined)
425
- return Result.Ok(EventoResult.Stop);
426
- const rRes = await api.subscribeDocs({
427
- ownerHandle: ctx.validated.ownerHandle,
428
- appSlug: ctx.validated.appSlug,
429
- dbName: ctx.validated.dbName,
430
- });
431
- if (rRes.isErr()) {
432
- await ctx.send.send(ctx, {
433
- tid: ctx.validated.tid,
434
- type: "vibes.diy.res-subscribe-docs",
435
- status: "error",
436
- message: rRes.Err().message,
437
- });
438
- }
439
- else {
440
- await ctx.send.send(ctx, {
441
- ...rRes.Ok(),
442
- tid: ctx.validated.tid,
443
- type: "vibes.diy.res-subscribe-docs",
444
- });
445
- }
446
- return Result.Ok(EventoResult.Stop);
447
- },
448
- };
449
- }
450
- function vibeSetDbAcl(sandbox) {
451
- return {
452
- hash: "vibe.setDbAcl",
453
- validate: (ctx) => {
454
- const { request: req } = ctx;
455
- if (isReqSetDbAcl(req?.data)) {
456
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
457
- }
458
- return Promise.resolve(Result.Ok(Option.None()));
459
- },
460
- handle: async (ctx) => {
461
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-set-db-acl");
462
- if (api === undefined)
463
- return Result.Ok(EventoResult.Stop);
464
- const rRes = await api.ensureAppSettings({
465
- ownerHandle: ctx.validated.ownerHandle,
466
- appSlug: ctx.validated.appSlug,
467
- dbAcl: { dbName: ctx.validated.dbName, acl: ctx.validated.acl },
468
- });
469
- if (rRes.isErr()) {
470
- await ctx.send.send(ctx, {
471
- tid: ctx.validated.tid,
472
- type: "vibes.diy.res-set-db-acl",
473
- status: "error",
474
- message: rRes.Err().message,
475
- });
476
- }
477
- else {
478
- await ctx.send.send(ctx, {
479
- tid: ctx.validated.tid,
480
- type: "vibes.diy.res-set-db-acl",
481
- status: "ok",
482
- });
483
- }
484
- return Result.Ok(EventoResult.Stop);
485
- },
486
- };
487
- }
488
- function vibeListDbNames(sandbox) {
489
- return {
490
- hash: "vibe.listDbNames",
491
- validate: (ctx) => {
492
- const { request: req } = ctx;
493
- if (isReqListDbNames(req?.data)) {
494
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
495
- }
496
- return Promise.resolve(Result.Ok(Option.None()));
497
- },
498
- handle: async (ctx) => {
499
- const api = await requireVibeApi(sandbox, ctx, "vibes.diy.res-list-db-names");
500
- if (api === undefined)
501
- return Result.Ok(EventoResult.Stop);
502
- const rRes = await api.listDbNames({
503
- ownerHandle: ctx.validated.ownerHandle,
504
- appSlug: ctx.validated.appSlug,
505
- });
506
- if (rRes.isErr()) {
507
- await ctx.send.send(ctx, {
508
- tid: ctx.validated.tid,
509
- type: "vibes.diy.res-list-db-names",
510
- status: "error",
511
- message: rRes.Err().message,
512
- });
513
- }
514
- else {
515
- await ctx.send.send(ctx, {
516
- ...rRes.Ok(),
517
- tid: ctx.validated.tid,
518
- });
519
- }
520
- return Result.Ok(EventoResult.Stop);
521
- },
522
- };
523
- }
524
- const PROGRESS_INTERVAL_MS = 3000;
525
- function vibePutAsset(sandbox) {
526
- const doFetch = sandbox.args.fetch ?? ((...a) => fetch(...a));
527
- return {
528
- hash: "vibe.putAsset",
529
- validate: (ctx) => {
530
- const { request: req } = ctx;
531
- if (isReqVibePutAsset(req?.data)) {
532
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
533
- }
534
- return Promise.resolve(Result.Ok(Option.None()));
535
- },
536
- handle: async (ctx) => {
537
- const api = await requireVibeApi(sandbox, ctx, "vibe.res.putAsset");
538
- if (api === undefined)
539
- return Result.Ok(EventoResult.Stop);
540
- const { tid, blob, ownerHandle, appSlug, mimeType } = ctx.validated;
541
- const sendErr = async (message) => {
542
- await ctx.send.send(ctx, {
543
- tid,
544
- type: "vibe.res.putAsset",
545
- status: "error",
546
- message,
547
- });
548
- };
549
- const rGrant = await api.requestAssetUploadGrant({
550
- ownerHandle,
551
- appSlug,
552
- ...(mimeType ? { mimeType } : mimeType === undefined && blob.type ? { mimeType: blob.type } : {}),
553
- });
554
- if (rGrant.isErr()) {
555
- await sendErr(`grant minting failed: ${rGrant.Err().message}`);
556
- return Result.Ok(EventoResult.Stop);
557
- }
558
- const grant = rGrant.Ok();
559
- const progressTimer = setInterval(() => {
560
- ctx.send.send(ctx, {
561
- tid,
562
- type: "vibe.evt.putAsset.progress",
563
- bytes: blob.size,
564
- });
565
- }, PROGRESS_INTERVAL_MS);
566
- try {
567
- const res = await doFetch(grant.uploadUrl, {
568
- method: "POST",
569
- headers: {
570
- "X-Asset-Grant": grant.grant,
571
- "Content-Type": blob.type || "application/octet-stream",
572
- },
573
- body: blob,
574
- });
575
- if (!res.ok) {
576
- const text = await res.text().catch(() => "");
577
- await sendErr(`POST ${grant.uploadUrl} returned ${res.status}: ${text}`);
578
- return Result.Ok(EventoResult.Stop);
579
- }
580
- const body = (await res.json());
581
- sandbox.recordAssetGetURL(body.cid, body.getURL);
582
- await ctx.send.send(ctx, {
583
- tid,
584
- type: "vibe.res.putAsset",
585
- status: "ok",
586
- cid: body.cid,
587
- getURL: body.getURL,
588
- size: body.size,
589
- uploadId: body.uploadId,
590
- });
591
- }
592
- catch (e) {
593
- const msg = e instanceof Error ? e.message : String(e);
594
- await sendErr(`upload failed: ${msg}`);
595
- }
596
- finally {
597
- clearInterval(progressTimer);
598
- }
599
- return Result.Ok(EventoResult.Stop);
600
- },
601
- };
602
- }
603
- function vibeWhoAmI(sandbox) {
604
- return {
605
- hash: "vibe.whoAmI",
606
- validate: (ctx) => {
607
- const { request: req } = ctx;
608
- if (isReqVibeWhoAmI(req?.data)) {
609
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
610
- }
611
- return Promise.resolve(Result.Ok(Option.None()));
612
- },
613
- handle: async (ctx) => {
614
- const api = await requireVibeApi(sandbox, ctx, "vibe.res.whoAmI");
615
- if (api === undefined)
616
- return Result.Ok(EventoResult.Stop);
617
- const { tid, appSlug, ownerHandle, adminMode } = ctx.validated;
618
- const rRes = await api.whoAmI({ tid, appSlug, ownerHandle, adminMode });
619
- if (rRes.isErr()) {
620
- await ctx.send.send(ctx, {
621
- tid,
622
- type: "vibe.res.whoAmI",
623
- viewer: null,
624
- access: "none",
625
- });
626
- return Result.Ok(EventoResult.Stop);
627
- }
628
- const r = rRes.Ok();
629
- await ctx.send.send(ctx, {
630
- tid,
631
- type: "vibe.res.whoAmI",
632
- viewer: r.viewer,
633
- access: r.access,
634
- ...(r.isOwner !== undefined ? { isOwner: r.isOwner } : {}),
635
- ...(r.dbAcls !== undefined ? { dbAcls: r.dbAcls } : {}),
636
- ...(r.grants !== undefined ? { grants: r.grants } : {}),
637
- });
638
- return Result.Ok(EventoResult.Stop);
639
- },
640
- };
641
- }
642
- function vibeUpdateAvatarCid(sandbox) {
643
- const { chatApi } = sandbox.args;
644
- return {
645
- hash: "vibe.updateAvatarCid",
646
- validate: (ctx) => {
647
- const { request: req } = ctx;
648
- if (isReqVibeUpdateAvatarCid(req?.data)) {
649
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
650
- }
651
- return Promise.resolve(Result.Ok(Option.None()));
652
- },
653
- handle: async (ctx) => {
654
- const { tid, cid, mimeType, handle } = ctx.validated;
655
- if (sandbox.args.confirmAvatarUpdate) {
656
- const getURL = sandbox.getAssetGetURL(cid);
657
- const confirmed = await sandbox.args.confirmAvatarUpdate({
658
- cid,
659
- ...(mimeType ? { mimeType } : {}),
660
- ...(getURL ? { getURL } : {}),
661
- });
662
- if (!confirmed) {
663
- await ctx.send.send(ctx, {
664
- tid,
665
- type: "vibe.res.updateAvatarCid",
666
- status: "cancelled",
667
- });
668
- return Result.Ok(EventoResult.Stop);
669
- }
670
- }
671
- const rRes = await chatApi.ensureHandleAvatar({
672
- handle,
673
- cid,
674
- ...(mimeType ? { mime: mimeType } : {}),
675
- });
676
- if (rRes.isErr()) {
677
- await ctx.send.send(ctx, {
678
- tid,
679
- type: "vibe.res.updateAvatarCid",
680
- status: "error",
681
- message: rRes.Err().message,
682
- });
683
- return Result.Ok(EventoResult.Stop);
684
- }
685
- await ctx.send.send(ctx, {
686
- tid,
687
- type: "vibe.res.updateAvatarCid",
688
- status: "ok",
689
- });
690
- return Result.Ok(EventoResult.Stop);
691
- },
692
- };
693
- }
694
- function vibeRequestLogin(sandbox) {
695
- return {
696
- hash: "vibe.requestLogin",
697
- validate: (ctx) => {
698
- const { request: req } = ctx;
699
- if (isReqVibeLogin(req?.data)) {
700
- return Promise.resolve(Result.Ok(Option.Some(req.data)));
701
- }
702
- return Promise.resolve(Result.Ok(Option.None()));
703
- },
704
- handle: async (_ctx) => {
705
- sandbox.args.openSignIn?.();
706
- return Result.Ok(EventoResult.Stop);
707
- },
708
- };
709
- }
710
43
  export class vibesDiySrvSandbox {
711
44
  evento;
712
45
  onRuntimeReady = OnFunc();