@poolse/sdk 2.0.3 → 2.0.5

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/dist/index.d.cts CHANGED
@@ -38,6 +38,18 @@ interface Conversation {
38
38
  settings: Record<string, unknown>;
39
39
  /** Most recent message's `inserted_at`; null until first message. */
40
40
  last_message_at: IsoDateTime | null;
41
+ /**
42
+ * Plaintext preview of the most recent message body, truncated to
43
+ * 80 chars. Updated server-side by `send_message`. Null when the
44
+ * conversation has no messages, or when the last message had no
45
+ * body (in which case `"📎 Attachment"` etc is returned).
46
+ *
47
+ * Note: stored unencrypted on the server (deliberate denorm so
48
+ * the conversation list doesn't pay a per-row decrypt). Apps with
49
+ * full at-rest-encryption requirements should ignore this field
50
+ * and render their own preview client-side.
51
+ */
52
+ last_message_preview: string | null;
41
53
  /** Monotonic per-conversation sequence counter (last message's `sequence`). */
42
54
  last_sequence: number;
43
55
  /**
@@ -47,6 +59,15 @@ interface Conversation {
47
59
  * conversation is fetched via other paths.
48
60
  */
49
61
  unread_count?: number;
62
+ /**
63
+ * Tenant `external_id`s of every member, in no particular order.
64
+ * Populated by code paths that preload the memberships
65
+ * (`chat.conversations.list()`); may be `[]` on responses where
66
+ * memberships weren't preloaded (webhook payloads, some create
67
+ * responses). Use this to render the other-party name on a direct
68
+ * conversation row without a separate `useMembers` call.
69
+ */
70
+ member_external_ids?: string[];
50
71
  inserted_at: IsoDateTime;
51
72
  updated_at: IsoDateTime;
52
73
  }
@@ -489,6 +510,21 @@ interface MentionEvent {
489
510
  * full conversation row.
490
511
  */
491
512
  type ConversationCreatedEvent = Conversation;
513
+ /**
514
+ * Pushed on `user:<id>` whenever a conversation's surface state
515
+ * changes — currently fires after every `send_message`. Lets the
516
+ * conversation-list view update `last_message_preview` /
517
+ * `last_message_at` / `last_sequence` and bump the unread badge
518
+ * without a refetch.
519
+ *
520
+ * `by_user_id` is the message sender's internal id, so clients can
521
+ * leave their own unread at 0 (the server already advanced their
522
+ * read cursor in the same transaction).
523
+ */
524
+ interface ConversationUpdatedEvent {
525
+ conversation: Conversation;
526
+ by_user_id: Uuid | null;
527
+ }
492
528
  /** Phoenix Presence list shape. */
493
529
  type PresenceSnapshot = Record<Uuid, {
494
530
  metas: Array<{
@@ -617,8 +653,10 @@ declare class UserChannel {
617
653
  private readonly channel;
618
654
  private readonly mentionListeners;
619
655
  private readonly conversationCreatedListeners;
656
+ private readonly conversationUpdatedListeners;
620
657
  private mentionBound;
621
658
  private conversationCreatedBound;
659
+ private conversationUpdatedBound;
622
660
  constructor(userId: string, channel: Channel);
623
661
  onMention(fn: (evt: MentionEvent) => void): Unsubscribe;
624
662
  /**
@@ -630,6 +668,17 @@ declare class UserChannel {
630
668
  * prepend it to a local list without a refetch.
631
669
  */
632
670
  onConversationCreated(fn: (conv: ConversationCreatedEvent) => void): Unsubscribe;
671
+ /**
672
+ * Subscribe to "an existing conversation changed" notifications —
673
+ * fires after every `send_message` in any conversation you're a
674
+ * member of. Use this to update the conversation-list row's last
675
+ * message preview, timestamp, and unread badge without polling.
676
+ *
677
+ * Compare `evt.by_user_id` to your own user id to decide whether
678
+ * to increment a local unread counter; the server already keeps
679
+ * your own outbound messages out of your unread count.
680
+ */
681
+ onConversationUpdated(fn: (evt: ConversationUpdatedEvent) => void): Unsubscribe;
633
682
  /** @internal */
634
683
  _join(): void;
635
684
  /** @internal */
@@ -1016,8 +1065,8 @@ declare class AuthError extends ApiError {
1016
1065
  constructor(envelope: ErrorEnvelope['error']);
1017
1066
  }
1018
1067
 
1019
- declare const version = "2.0.3";
1068
+ declare const version = "2.0.2";
1020
1069
 
1021
1070
  declare function safeUuid(): string;
1022
1071
 
1023
- export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, type AttachmentProgressEvent, type AttachmentStatus, type AttachmentUploadInput, type AttachmentUploadRequest, type AttachmentUploadResponse, AttachmentsResource, AuthError, type Conversation, ConversationChannel, type ConversationCreateRequest, type ConversationCreatedEvent, ConversationHandle, type ConversationList, ConversationMessages, type ConversationType, type ConversationUpdateRequest, ConversationsResource, type ErrorEnvelope, type IsoDateTime, type Me, MeResource, type MemberReadEvent, type MemberRole, type Membership, type MembershipCreateRequest, type MembershipList, type MentionEvent, type Message, type MessageCreateRequest, type MessageDeletedEvent, MessageHandle, type MessageList, type MessageNewEvent, type MessageType, type MessageUpdateRequest, type MessageUpdatedEvent, MessagesResource, NetworkError, POOLSE_API_URL, Poolse, type PoolseConfig, PoolseError, PoolseRealtime, type PoolseUserProfile, type PresenceSnapshot, type QuotedMessagePreview, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, UsersResource, type Uuid, safeUuid, version };
1072
+ export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, type AttachmentProgressEvent, type AttachmentStatus, type AttachmentUploadInput, type AttachmentUploadRequest, type AttachmentUploadResponse, AttachmentsResource, AuthError, type Conversation, ConversationChannel, type ConversationCreateRequest, type ConversationCreatedEvent, ConversationHandle, type ConversationList, ConversationMessages, type ConversationType, type ConversationUpdateRequest, type ConversationUpdatedEvent, ConversationsResource, type ErrorEnvelope, type IsoDateTime, type Me, MeResource, type MemberReadEvent, type MemberRole, type Membership, type MembershipCreateRequest, type MembershipList, type MentionEvent, type Message, type MessageCreateRequest, type MessageDeletedEvent, MessageHandle, type MessageList, type MessageNewEvent, type MessageType, type MessageUpdateRequest, type MessageUpdatedEvent, MessagesResource, NetworkError, POOLSE_API_URL, Poolse, type PoolseConfig, PoolseError, PoolseRealtime, type PoolseUserProfile, type PresenceSnapshot, type QuotedMessagePreview, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, UsersResource, type Uuid, safeUuid, version };
package/dist/index.d.ts CHANGED
@@ -38,6 +38,18 @@ interface Conversation {
38
38
  settings: Record<string, unknown>;
39
39
  /** Most recent message's `inserted_at`; null until first message. */
40
40
  last_message_at: IsoDateTime | null;
41
+ /**
42
+ * Plaintext preview of the most recent message body, truncated to
43
+ * 80 chars. Updated server-side by `send_message`. Null when the
44
+ * conversation has no messages, or when the last message had no
45
+ * body (in which case `"📎 Attachment"` etc is returned).
46
+ *
47
+ * Note: stored unencrypted on the server (deliberate denorm so
48
+ * the conversation list doesn't pay a per-row decrypt). Apps with
49
+ * full at-rest-encryption requirements should ignore this field
50
+ * and render their own preview client-side.
51
+ */
52
+ last_message_preview: string | null;
41
53
  /** Monotonic per-conversation sequence counter (last message's `sequence`). */
42
54
  last_sequence: number;
43
55
  /**
@@ -47,6 +59,15 @@ interface Conversation {
47
59
  * conversation is fetched via other paths.
48
60
  */
49
61
  unread_count?: number;
62
+ /**
63
+ * Tenant `external_id`s of every member, in no particular order.
64
+ * Populated by code paths that preload the memberships
65
+ * (`chat.conversations.list()`); may be `[]` on responses where
66
+ * memberships weren't preloaded (webhook payloads, some create
67
+ * responses). Use this to render the other-party name on a direct
68
+ * conversation row without a separate `useMembers` call.
69
+ */
70
+ member_external_ids?: string[];
50
71
  inserted_at: IsoDateTime;
51
72
  updated_at: IsoDateTime;
52
73
  }
@@ -489,6 +510,21 @@ interface MentionEvent {
489
510
  * full conversation row.
490
511
  */
491
512
  type ConversationCreatedEvent = Conversation;
513
+ /**
514
+ * Pushed on `user:<id>` whenever a conversation's surface state
515
+ * changes — currently fires after every `send_message`. Lets the
516
+ * conversation-list view update `last_message_preview` /
517
+ * `last_message_at` / `last_sequence` and bump the unread badge
518
+ * without a refetch.
519
+ *
520
+ * `by_user_id` is the message sender's internal id, so clients can
521
+ * leave their own unread at 0 (the server already advanced their
522
+ * read cursor in the same transaction).
523
+ */
524
+ interface ConversationUpdatedEvent {
525
+ conversation: Conversation;
526
+ by_user_id: Uuid | null;
527
+ }
492
528
  /** Phoenix Presence list shape. */
493
529
  type PresenceSnapshot = Record<Uuid, {
494
530
  metas: Array<{
@@ -617,8 +653,10 @@ declare class UserChannel {
617
653
  private readonly channel;
618
654
  private readonly mentionListeners;
619
655
  private readonly conversationCreatedListeners;
656
+ private readonly conversationUpdatedListeners;
620
657
  private mentionBound;
621
658
  private conversationCreatedBound;
659
+ private conversationUpdatedBound;
622
660
  constructor(userId: string, channel: Channel);
623
661
  onMention(fn: (evt: MentionEvent) => void): Unsubscribe;
624
662
  /**
@@ -630,6 +668,17 @@ declare class UserChannel {
630
668
  * prepend it to a local list without a refetch.
631
669
  */
632
670
  onConversationCreated(fn: (conv: ConversationCreatedEvent) => void): Unsubscribe;
671
+ /**
672
+ * Subscribe to "an existing conversation changed" notifications —
673
+ * fires after every `send_message` in any conversation you're a
674
+ * member of. Use this to update the conversation-list row's last
675
+ * message preview, timestamp, and unread badge without polling.
676
+ *
677
+ * Compare `evt.by_user_id` to your own user id to decide whether
678
+ * to increment a local unread counter; the server already keeps
679
+ * your own outbound messages out of your unread count.
680
+ */
681
+ onConversationUpdated(fn: (evt: ConversationUpdatedEvent) => void): Unsubscribe;
633
682
  /** @internal */
634
683
  _join(): void;
635
684
  /** @internal */
@@ -1016,8 +1065,8 @@ declare class AuthError extends ApiError {
1016
1065
  constructor(envelope: ErrorEnvelope['error']);
1017
1066
  }
1018
1067
 
1019
- declare const version = "2.0.3";
1068
+ declare const version = "2.0.2";
1020
1069
 
1021
1070
  declare function safeUuid(): string;
1022
1071
 
1023
- export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, type AttachmentProgressEvent, type AttachmentStatus, type AttachmentUploadInput, type AttachmentUploadRequest, type AttachmentUploadResponse, AttachmentsResource, AuthError, type Conversation, ConversationChannel, type ConversationCreateRequest, type ConversationCreatedEvent, ConversationHandle, type ConversationList, ConversationMessages, type ConversationType, type ConversationUpdateRequest, ConversationsResource, type ErrorEnvelope, type IsoDateTime, type Me, MeResource, type MemberReadEvent, type MemberRole, type Membership, type MembershipCreateRequest, type MembershipList, type MentionEvent, type Message, type MessageCreateRequest, type MessageDeletedEvent, MessageHandle, type MessageList, type MessageNewEvent, type MessageType, type MessageUpdateRequest, type MessageUpdatedEvent, MessagesResource, NetworkError, POOLSE_API_URL, Poolse, type PoolseConfig, PoolseError, PoolseRealtime, type PoolseUserProfile, type PresenceSnapshot, type QuotedMessagePreview, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, UsersResource, type Uuid, safeUuid, version };
1072
+ export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, type AttachmentProgressEvent, type AttachmentStatus, type AttachmentUploadInput, type AttachmentUploadRequest, type AttachmentUploadResponse, AttachmentsResource, AuthError, type Conversation, ConversationChannel, type ConversationCreateRequest, type ConversationCreatedEvent, ConversationHandle, type ConversationList, ConversationMessages, type ConversationType, type ConversationUpdateRequest, type ConversationUpdatedEvent, ConversationsResource, type ErrorEnvelope, type IsoDateTime, type Me, MeResource, type MemberReadEvent, type MemberRole, type Membership, type MembershipCreateRequest, type MembershipList, type MentionEvent, type Message, type MessageCreateRequest, type MessageDeletedEvent, MessageHandle, type MessageList, type MessageNewEvent, type MessageType, type MessageUpdateRequest, type MessageUpdatedEvent, MessagesResource, NetworkError, POOLSE_API_URL, Poolse, type PoolseConfig, PoolseError, PoolseRealtime, type PoolseUserProfile, type PresenceSnapshot, type QuotedMessagePreview, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, UsersResource, type Uuid, safeUuid, version };
package/dist/index.js CHANGED
@@ -2,26 +2,16 @@ import { Socket } from 'phoenix';
2
2
 
3
3
  // src/uuid.ts
4
4
  function safeUuid() {
5
- try {
6
- const c = globalThis.crypto;
7
- if (c && typeof c.randomUUID === "function") {
8
- const out = c.randomUUID();
9
- if (typeof out === "string") return out;
10
- }
11
- if (c && typeof c.getRandomValues === "function") {
12
- const bytes = new Uint8Array(16);
13
- c.getRandomValues(bytes);
14
- return formatV4(bytes);
5
+ const c = globalThis.crypto;
6
+ if (c?.randomUUID) return c.randomUUID();
7
+ const bytes = new Uint8Array(16);
8
+ if (c?.getRandomValues) {
9
+ c.getRandomValues(bytes);
10
+ } else {
11
+ for (let i = 0; i < 16; i++) {
12
+ bytes[i] = Math.floor(Math.random() * 256);
15
13
  }
16
- } catch {
17
14
  }
18
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
19
- const r = Math.random() * 16 | 0;
20
- const v = ch === "x" ? r : r & 3 | 8;
21
- return v.toString(16);
22
- });
23
- }
24
- function formatV4(bytes) {
25
15
  bytes[6] = bytes[6] & 15 | 64;
26
16
  bytes[8] = bytes[8] & 63 | 128;
27
17
  const hex = [];
@@ -366,8 +356,10 @@ var UserChannel = class {
366
356
  channel;
367
357
  mentionListeners = /* @__PURE__ */ new Set();
368
358
  conversationCreatedListeners = /* @__PURE__ */ new Set();
359
+ conversationUpdatedListeners = /* @__PURE__ */ new Set();
369
360
  mentionBound = false;
370
361
  conversationCreatedBound = false;
362
+ conversationUpdatedBound = false;
371
363
  constructor(userId, channel) {
372
364
  this.userId = userId;
373
365
  this.channel = channel;
@@ -404,6 +396,28 @@ var UserChannel = class {
404
396
  this.conversationCreatedListeners.delete(fn);
405
397
  };
406
398
  }
399
+ /**
400
+ * Subscribe to "an existing conversation changed" notifications —
401
+ * fires after every `send_message` in any conversation you're a
402
+ * member of. Use this to update the conversation-list row's last
403
+ * message preview, timestamp, and unread badge without polling.
404
+ *
405
+ * Compare `evt.by_user_id` to your own user id to decide whether
406
+ * to increment a local unread counter; the server already keeps
407
+ * your own outbound messages out of your unread count.
408
+ */
409
+ onConversationUpdated(fn) {
410
+ if (!this.conversationUpdatedBound) {
411
+ this.conversationUpdatedBound = true;
412
+ this.channel.on("conversation:updated", (payload) => {
413
+ this.conversationUpdatedListeners.forEach((l) => l(payload));
414
+ });
415
+ }
416
+ this.conversationUpdatedListeners.add(fn);
417
+ return () => {
418
+ this.conversationUpdatedListeners.delete(fn);
419
+ };
420
+ }
407
421
  /** @internal */
408
422
  _join() {
409
423
  this.channel.join();
@@ -412,6 +426,7 @@ var UserChannel = class {
412
426
  _destroy() {
413
427
  this.mentionListeners.clear();
414
428
  this.conversationCreatedListeners.clear();
429
+ this.conversationUpdatedListeners.clear();
415
430
  this.channel.leave();
416
431
  }
417
432
  };
@@ -1189,7 +1204,7 @@ var Poolse = class {
1189
1204
  };
1190
1205
 
1191
1206
  // src/version.ts
1192
- var version = "2.0.3";
1207
+ var version = "2.0.2";
1193
1208
 
1194
1209
  export { ApiError, AttachmentHandle, AttachmentsResource, AuthError, ConversationChannel, ConversationHandle, ConversationMessages, ConversationsResource, MeResource, MessageHandle, MessagesResource, NetworkError, POOLSE_API_URL, Poolse, PoolseError, PoolseRealtime, RateLimitedError, UserChannel, UsersResource, safeUuid, version };
1195
1210
  //# sourceMappingURL=index.js.map