@pmate/chat-sdk 0.12.0-next.43 → 0.12.0-next.44
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.
|
@@ -205,7 +205,7 @@ export class DurableChatSender {
|
|
|
205
205
|
if (!(input.voiceBlob instanceof Blob) || input.voiceBlob.size === 0 || input.voiceBlob.size > 16 * 1024 * 1024 || body.kind !== "message" || !validVoice(body.content.voice))
|
|
206
206
|
throw new Error("INVALID_VOICE_ATTACHMENT");
|
|
207
207
|
}
|
|
208
|
-
const record = { ...(input.voiceBlob ? { voiceBlob: input.voiceBlob } : {}), scope: this.scope, threadId, hash: message.hash, message, status: "sending", accessVersion: this.version };
|
|
208
|
+
const record = { ...(input.voiceBlob ? { voiceData: { bytes: await input.voiceBlob.arrayBuffer(), type: input.voiceBlob.type } } : {}), scope: this.scope, threadId, hash: message.hash, message, status: "sending", accessVersion: this.version };
|
|
209
209
|
await this.withEpoch("rw", async () => { await this.outbox.put(record); });
|
|
210
210
|
await this.checkAccess();
|
|
211
211
|
this.values.set(record.hash, record);
|
|
@@ -244,7 +244,7 @@ export class DurableChatSender {
|
|
|
244
244
|
this.emit();
|
|
245
245
|
}
|
|
246
246
|
try {
|
|
247
|
-
if (record
|
|
247
|
+
if (hasVoice(record)) {
|
|
248
248
|
record = await this.prepareVoice(record);
|
|
249
249
|
if (record.confirmed || record.status === "sent")
|
|
250
250
|
return record.message;
|
|
@@ -289,18 +289,19 @@ export class DurableChatSender {
|
|
|
289
289
|
releaseUrls() { for (const hash of this.localUrls.keys())
|
|
290
290
|
this.releaseUrl(hash); }
|
|
291
291
|
localView(record) {
|
|
292
|
-
if (!record
|
|
292
|
+
if (!hasVoice(record) || typeof URL.createObjectURL !== "function")
|
|
293
293
|
return record;
|
|
294
294
|
let cached = this.localViews.get(record);
|
|
295
295
|
if (cached)
|
|
296
296
|
return cached;
|
|
297
|
+
const blob = voiceBlob(record);
|
|
297
298
|
let local = this.localUrls.get(record.hash);
|
|
298
|
-
if (!local || local.blob !==
|
|
299
|
+
if (!local || local.blob !== blob) {
|
|
299
300
|
this.releaseUrl(record.hash);
|
|
300
|
-
local = { blob
|
|
301
|
+
local = { blob, url: URL.createObjectURL(blob) };
|
|
301
302
|
this.localUrls.set(record.hash, local);
|
|
302
303
|
}
|
|
303
|
-
cached = { ...record, message: withVoiceUrl(record.message, local.url) };
|
|
304
|
+
cached = { ...record, voiceBlob: blob, message: withVoiceUrl(record.message, local.url) };
|
|
304
305
|
this.localViews.set(record, cached);
|
|
305
306
|
return cached;
|
|
306
307
|
}
|
|
@@ -319,7 +320,7 @@ export class DurableChatSender {
|
|
|
319
320
|
const latest = await this.withEpoch("r", () => this.outbox.get([this.scope, record.hash]));
|
|
320
321
|
if (!latest)
|
|
321
322
|
throw new Error("OUTGOING_MESSAGE_UNAVAILABLE");
|
|
322
|
-
if (!latest
|
|
323
|
+
if (!hasVoice(latest) || latest.confirmed || latest.status === "sent")
|
|
323
324
|
return latest;
|
|
324
325
|
if (!this.options.uploadVoice)
|
|
325
326
|
throw new Error("VOICE_UPLOAD_UNAVAILABLE");
|
|
@@ -328,7 +329,7 @@ export class DurableChatSender {
|
|
|
328
329
|
const timeout = setTimeout(() => controller.abort(), 30_000);
|
|
329
330
|
let url;
|
|
330
331
|
try {
|
|
331
|
-
url = await this.options.uploadVoice(latest
|
|
332
|
+
url = await this.options.uploadVoice(voiceBlob(latest), controller.signal);
|
|
332
333
|
}
|
|
333
334
|
finally {
|
|
334
335
|
clearTimeout(timeout);
|
|
@@ -340,10 +341,10 @@ export class DurableChatSender {
|
|
|
340
341
|
await this.checkAccess();
|
|
341
342
|
if (this.closing)
|
|
342
343
|
throw new Error("CHAT_SENDER_CLOSED");
|
|
343
|
-
const { voiceBlob: _blob, ...uploaded } = latest;
|
|
344
|
+
const { voiceBlob: _blob, voiceData: _data, ...uploaded } = latest;
|
|
344
345
|
const committed = await this.withEpoch("rw", async () => {
|
|
345
346
|
const current = await this.outbox.get([this.scope, record.hash]);
|
|
346
|
-
if (!current || current.confirmed || current.status === "sent" || !current
|
|
347
|
+
if (!current || current.confirmed || current.status === "sent" || !hasVoice(current))
|
|
347
348
|
return current;
|
|
348
349
|
const next = { ...uploaded, message: withVoiceUrl(latest.message, url) };
|
|
349
350
|
await this.outbox.put(next);
|
|
@@ -366,7 +367,7 @@ export class DurableChatSender {
|
|
|
366
367
|
if (!previous || previous.confirmed || previous.status === "sent")
|
|
367
368
|
return previous;
|
|
368
369
|
// A second document may already have durably replaced the Blob with its URL.
|
|
369
|
-
if (record
|
|
370
|
+
if (hasVoice(record) && !hasVoice(previous))
|
|
370
371
|
return previous;
|
|
371
372
|
await this.outbox.put(record);
|
|
372
373
|
return record;
|
|
@@ -381,7 +382,7 @@ export class DurableChatSender {
|
|
|
381
382
|
await this.ready;
|
|
382
383
|
await this.withEpoch("rw", async () => {
|
|
383
384
|
const previous = await this.outbox.bulkGet(hashes.map(hash => [this.scope, hash]));
|
|
384
|
-
const confirmed = previous.filter((record) => Boolean(record && !record.confirmed)).map(record => ({ ...record, voiceBlob: undefined, status: "sent", confirmed: true }));
|
|
385
|
+
const confirmed = previous.filter((record) => Boolean(record && !record.confirmed)).map(record => ({ ...record, voiceBlob: undefined, voiceData: undefined, status: "sent", confirmed: true }));
|
|
385
386
|
if (confirmed.length)
|
|
386
387
|
await this.outbox.bulkPut(confirmed);
|
|
387
388
|
});
|
|
@@ -435,3 +436,5 @@ function withVoiceUrl(message, url) {
|
|
|
435
436
|
const body = message.body;
|
|
436
437
|
return { ...message, body: { ...body, content: { ...body.content, voice: { ...body.content.voice, url } } } };
|
|
437
438
|
}
|
|
439
|
+
function hasVoice(record) { return Boolean(record.voiceBlob || record.voiceData); }
|
|
440
|
+
function voiceBlob(record) { return record.voiceBlob ?? new Blob([record.voiceData.bytes], { type: record.voiceData.type }); }
|
package/package.json
CHANGED