@robono/messaging-react-native 0.0.0-stage → 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 (76) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +130 -0
  3. package/README.md +240 -2
  4. package/SBOM.spdx.json +1847 -0
  5. package/app.plugin.cjs +5 -0
  6. package/dist/call-message.d.ts +6 -0
  7. package/dist/call-message.js +109 -0
  8. package/dist/calling.d.ts +15 -0
  9. package/dist/calling.js +22 -0
  10. package/dist/expo-calling.d.ts +6 -0
  11. package/dist/expo-calling.js +7 -0
  12. package/dist/expo-download.d.ts +3 -0
  13. package/dist/expo-download.js +43 -0
  14. package/dist/expo-media.d.ts +19 -0
  15. package/dist/expo-media.js +411 -0
  16. package/dist/expo-outbox.d.ts +13 -0
  17. package/dist/expo-outbox.js +81 -0
  18. package/dist/expo-saved.d.ts +24 -0
  19. package/dist/expo-saved.js +76 -0
  20. package/dist/expo-social.d.ts +3 -0
  21. package/dist/expo-social.js +21 -0
  22. package/dist/expo-thumbnails.d.ts +9 -0
  23. package/dist/expo-thumbnails.js +68 -0
  24. package/dist/expo.d.ts +42 -0
  25. package/dist/expo.js +549 -0
  26. package/dist/forward.d.ts +13 -0
  27. package/dist/forward.js +61 -0
  28. package/dist/icons.d.ts +7 -0
  29. package/dist/icons.js +10 -0
  30. package/dist/inbox.d.ts +16 -0
  31. package/dist/inbox.js +48 -0
  32. package/dist/index.d.ts +144 -0
  33. package/dist/index.js +696 -0
  34. package/dist/media-controller.d.ts +116 -0
  35. package/dist/media-controller.js +372 -0
  36. package/dist/media-readiness.d.ts +4 -0
  37. package/dist/media-readiness.js +4 -0
  38. package/dist/media-ui.d.ts +62 -0
  39. package/dist/media-ui.js +46 -0
  40. package/dist/message-links.d.ts +5 -0
  41. package/dist/message-links.js +30 -0
  42. package/dist/message-order.d.ts +4 -0
  43. package/dist/message-order.js +17 -0
  44. package/dist/native-outbox.d.ts +49 -0
  45. package/dist/native-outbox.js +51 -0
  46. package/dist/pollVoteQueue.d.ts +3 -0
  47. package/dist/pollVoteQueue.js +29 -0
  48. package/dist/polls.d.ts +25 -0
  49. package/dist/polls.js +121 -0
  50. package/dist/popup.d.ts +9 -0
  51. package/dist/popup.js +7 -0
  52. package/dist/recent-media.d.ts +21 -0
  53. package/dist/recent-media.js +123 -0
  54. package/dist/safety.d.ts +12 -0
  55. package/dist/safety.js +53 -0
  56. package/dist/saved.d.ts +10 -0
  57. package/dist/saved.js +46 -0
  58. package/dist/search.d.ts +9 -0
  59. package/dist/search.js +41 -0
  60. package/dist/social.d.ts +19 -0
  61. package/dist/social.js +35 -0
  62. package/dist/use-quote-gesture.d.ts +24 -0
  63. package/dist/use-quote-gesture.js +127 -0
  64. package/dist/visual/RobonoIcon.d.ts +232 -0
  65. package/dist/visual/RobonoIcon.js +21 -0
  66. package/dist/visual/icon-nodes.d.ts +3 -0
  67. package/dist/visual/icon-nodes.js +2 -0
  68. package/dist/visual/icon-paths.d.ts +221 -0
  69. package/dist/visual/icon-paths.js +221 -0
  70. package/dist/voice-composer.d.ts +37 -0
  71. package/dist/voice-composer.js +20 -0
  72. package/licenses/robono-icons-lucide-license.txt +43 -0
  73. package/licenses/robono-icons-weather-attribution.txt +1 -0
  74. package/licenses/robono-icons-weather-license.txt +21 -0
  75. package/package.json +126 -4
  76. package/plugin/preserve-call-audio.cjs +22 -0
@@ -0,0 +1,68 @@
1
+ import * as ImageManipulator from 'expo-image-manipulator';
2
+ import * as VideoThumbnails from 'expo-video-thumbnails';
3
+ import * as FS from 'expo-file-system/legacy';
4
+ /** Small local previews, with bounded downloads and memory. Large originals stay
5
+ * tap-to-open until the storage service supplies a dedicated thumbnail. */
6
+ export function createExpoThumbnails(storage, local, remove) {
7
+ let generation = 0;
8
+ const cache = new Map(), abort = new Set();
9
+ let queue = Promise.resolve();
10
+ function clear() { generation++; cache.clear(); for (const c of abort)
11
+ c.abort(); abort.clear(); }
12
+ function preview(message) {
13
+ const media = message.media;
14
+ if (!media || message.deleted)
15
+ return Promise.resolve({});
16
+ if (message.kind === 'voice')
17
+ return Promise.resolve({ waveform: media.waveform });
18
+ if (!['image', 'video'].includes(message.kind))
19
+ return Promise.resolve({});
20
+ const id = media.assetId, existing = cache.get(id);
21
+ if (existing)
22
+ return existing;
23
+ const g = generation;
24
+ const work = queue.then(async () => {
25
+ if (g !== generation)
26
+ return {};
27
+ let file = local(id), downloaded = false, poster, thumbnail;
28
+ const controller = new AbortController();
29
+ abort.add(controller);
30
+ try {
31
+ let dedicated = false;
32
+ if (!file && storage.thumbnail) {
33
+ file = await storage.thumbnail(message, { signal: controller.signal, onProgress: () => { } }).catch(() => null) ?? undefined;
34
+ dedicated = !!file;
35
+ downloaded = !!file;
36
+ }
37
+ if (!file) {
38
+ if (media.byteSize > 2 * 1024 * 1024)
39
+ return {};
40
+ file = await storage.download(message, { signal: controller.signal, onProgress: () => { } });
41
+ downloaded = true;
42
+ }
43
+ if (g !== generation)
44
+ return {};
45
+ if (message.kind === 'video' && !dedicated)
46
+ poster = (await VideoThumbnails.getThumbnailAsync(file.uri, { time: 0, quality: .6 })).uri;
47
+ const result = await ImageManipulator.manipulateAsync(poster ?? file.uri, [{ resize: { width: 480 } }], { compress: .7, format: ImageManipulator.SaveFormat.JPEG, base64: true });
48
+ thumbnail = result.uri;
49
+ return g === generation && result.base64 ? { uri: 'data:image/jpeg;base64,' + result.base64 } : {};
50
+ }
51
+ finally {
52
+ abort.delete(controller);
53
+ if (downloaded && file)
54
+ await remove(file).catch(() => { });
55
+ for (const uri of [poster, thumbnail])
56
+ if (uri && FS.cacheDirectory && uri.startsWith(FS.cacheDirectory))
57
+ await FS.deleteAsync(uri, { idempotent: true }).catch(() => { });
58
+ }
59
+ }).catch(() => ({}));
60
+ queue = work.then(() => { });
61
+ cache.set(id, work);
62
+ if (cache.size > 100)
63
+ cache.delete(cache.keys().next().value);
64
+ return work;
65
+ }
66
+ return { preview, clear, alias: (from, to) => { const value = cache.get(from); if (value)
67
+ cache.set(to, value); } };
68
+ }
package/dist/expo.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ export { createExpoMessagingClient } from './expo-outbox.js';
2
+ import React from 'react';
3
+ import { type MessagingAppearance } from '@robono/messaging';
4
+ import { type MessagingScreenProps } from './index.js';
5
+ import { MessagingMediaController, type LocalMessagingMedia, type MessagingMediaStorage } from './media-controller.js';
6
+ import { type MediaReadyStage } from './media-readiness.js';
7
+ import { type MessagingAudioSession } from './expo-media.js';
8
+ export { createExpoMessagingAudioSession, createExpoMessagingDevice, createExpoMessagingStorage } from './expo-media.js';
9
+ export type { MessagingAudioSession } from './expo-media.js';
10
+ export type { LocalMessagingMedia, MessagingMediaStorage, MediaTransferOptions } from './media-controller.js';
11
+ export { MessagingMediaController } from './media-controller.js';
12
+ export declare function MessagingMediaOverlay({ controller, audio, appearance, inlineVoice, inlineRecorder, viewerActions, onDismiss }: {
13
+ onDismiss?: () => void;
14
+ viewerActions?: () => {
15
+ onForward?: () => void;
16
+ onDelete?: () => void;
17
+ };
18
+ controller: MessagingMediaController;
19
+ audio: MessagingAudioSession;
20
+ appearance: MessagingAppearance;
21
+ inlineVoice?: boolean | (() => boolean);
22
+ inlineRecorder?: boolean | (() => boolean);
23
+ }): React.JSX.Element | null;
24
+ export interface ExpoMessagingScreenProps extends Omit<MessagingScreenProps, 'pickAttachment' | 'openAttachment'> {
25
+ storage: MessagingMediaStorage;
26
+ audioSession: MessagingAudioSession;
27
+ /** Optional timing callback from native image/frame/playback readiness, measured from opening. */
28
+ onMediaReady?: (event: {
29
+ messageId: string;
30
+ kind: string;
31
+ stage: MediaReadyStage;
32
+ elapsedMs: number;
33
+ }) => void;
34
+ /** Preload a bounded set of small recent attachments while this conversation is open. Default true. */
35
+ preloadRecentMedia?: boolean;
36
+ /** Compose a conversation with the supplied media adapters. */
37
+ renderConversation?: (props: MessagingScreenProps) => React.ReactNode;
38
+ /** Resolve an authorized recent attachment to an adapter-owned cache copy, never a library original. */
39
+ resolveAttachmentChoice?: (id: string, signal: AbortSignal) => Promise<LocalMessagingMedia | null>;
40
+ }
41
+ /** Optional ready-made recording, preview, upload and download tools for both mobile platforms. */
42
+ export declare function ExpoMessagingScreen({ storage, audioSession, renderConversation, preloadRecentMedia, ...props }: ExpoMessagingScreenProps): React.JSX.Element;