@poolse/sdk 0.1.0 → 0.2.0-alpha.3

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
@@ -1,14 +1,23 @@
1
1
  import { Channel } from 'phoenix';
2
2
 
3
+ /**
4
+ * Hosted poolse API URL. Used as the default for `PoolseConfig.apiUrl`
5
+ * when you don't pass one — appropriate for the vast majority of
6
+ * integrations that target the official poolse cloud. Self-hosted /
7
+ * staging deployments override via the `apiUrl` field.
8
+ */
9
+ declare const POOLSE_API_URL = "https://api.poolse.dev";
3
10
  /**
4
11
  * SDK configuration passed to `new Poolse(config)`.
5
12
  */
6
13
  interface PoolseConfig {
7
14
  /**
8
- * Base URL of the poolse REST API, e.g. `https://chat.example.com`.
9
- * MUST NOT include the `/v1` path the SDK adds that itself.
15
+ * Base URL of the poolse REST API. Defaults to the hosted endpoint
16
+ * at `https://api.poolse.dev`. Override only for self-hosted /
17
+ * staging deployments. MUST NOT include the `/v1` path — the SDK
18
+ * adds that itself.
10
19
  */
11
- apiUrl: string;
20
+ apiUrl?: string;
12
21
  /**
13
22
  * Async hook the SDK calls every time it needs an `Authorization:
14
23
  * Bearer <jwt>` header. Most apps refresh the JWT from their own
@@ -146,6 +155,13 @@ interface Conversation {
146
155
  last_message_at: IsoDateTime | null;
147
156
  /** Monotonic per-conversation sequence counter (last message's `sequence`). */
148
157
  last_sequence: number;
158
+ /**
159
+ * Number of messages the caller hasn't read yet
160
+ * (`last_sequence - sequence_of(my_last_read_message_id)`).
161
+ * Populated only by `chat.conversations.list()` — undefined when the
162
+ * conversation is fetched via other paths.
163
+ */
164
+ unread_count?: number;
149
165
  inserted_at: IsoDateTime;
150
166
  updated_at: IsoDateTime;
151
167
  }
@@ -213,6 +229,13 @@ interface Message {
213
229
  thread_root_id: Uuid | null;
214
230
  mentions: Uuid[];
215
231
  reactions: Record<string, Uuid[]>;
232
+ /**
233
+ * Attachments linked to this message. Server populates on send +
234
+ * realtime broadcast; absent on partial responses (e.g. when the
235
+ * client posted with attachment_ids but the server has yet to
236
+ * resolve them).
237
+ */
238
+ attachments?: Attachment[];
216
239
  edited_at: IsoDateTime | null;
217
240
  deleted_at: IsoDateTime | null;
218
241
  sequence: number;
@@ -223,10 +246,31 @@ interface MessageList {
223
246
  data: Message[];
224
247
  }
225
248
  interface MessageCreateRequest {
226
- body: string;
249
+ /**
250
+ * Plain-text body. Optional only when `attachment_ids` is non-empty
251
+ * — a message with attachments AND no body is valid (just the
252
+ * attachment renders). At least one of `body` or `attachment_ids`
253
+ * must be present.
254
+ */
255
+ body?: string | null;
227
256
  type?: MessageType;
228
257
  reply_to_id?: Uuid;
229
258
  mentions?: Uuid[];
259
+ /**
260
+ * Attach previously-uploaded attachments to this message. Each id
261
+ * must come from `chat.attachments.upload(...)` or the lower-level
262
+ * `requestUpload(...)` flow and must belong to the same tenant.
263
+ * The server links them in the same transaction as the insert, so
264
+ * the broadcast and REST response both carry the resolved
265
+ * `Attachment` rows in `message.attachments`.
266
+ */
267
+ attachment_ids?: Uuid[];
268
+ /**
269
+ * Client-supplied UUID for retry-safe sends. The SDK fills this in
270
+ * automatically when not provided so the optimistic temp row and
271
+ * the canonical server row share a single id (used for id-based
272
+ * dedup in `useMessages`).
273
+ */
230
274
  id?: Uuid;
231
275
  }
232
276
  interface MessageUpdateRequest {
@@ -304,6 +348,18 @@ interface ReactionEvent {
304
348
  emoji: string;
305
349
  user_id: Uuid;
306
350
  }
351
+ /**
352
+ * `member:read` — a conversation member advanced their read cursor.
353
+ * Server broadcasts on `conversation:<id>` so the sender's
354
+ * read-receipt glyph (check vs check-double) updates in real time
355
+ * without needing to refetch the member list.
356
+ */
357
+ interface MemberReadEvent {
358
+ user_id: Uuid;
359
+ conversation_id: Uuid;
360
+ last_read_message_id: Uuid;
361
+ last_read_at: string;
362
+ }
307
363
  /** Per-user mention push on the `user:<id>` channel. */
308
364
  interface MentionEvent {
309
365
  message_id: Uuid;
@@ -421,6 +477,11 @@ declare class ConversationChannel {
421
477
  onTypingStop(fn: (evt: TypingEvent) => void): Unsubscribe;
422
478
  onReactionAdded(fn: (evt: ReactionEvent) => void): Unsubscribe;
423
479
  onReactionRemoved(fn: (evt: ReactionEvent) => void): Unsubscribe;
480
+ /**
481
+ * A conversation member advanced their read cursor. Used to flip the
482
+ * sender's read-receipt glyph from "sent" to "read" in real time.
483
+ */
484
+ onMemberRead(fn: (evt: MemberReadEvent) => void): Unsubscribe;
424
485
  onPresenceState(fn: (state: PresenceSnapshot) => void): Unsubscribe;
425
486
  onPresenceDiff(fn: (diff: PresenceSnapshot) => void): Unsubscribe;
426
487
  /** Send a typing ping to the server. Debounced server-side. */
@@ -772,4 +833,4 @@ declare class AuthError extends ApiError {
772
833
 
773
834
  declare const version = "0.0.1";
774
835
 
775
- export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, 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 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, type PoolseConfig, PoolseError, PoolseRealtime, type PresenceSnapshot, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, type Uuid, version };
836
+ export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, 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 PresenceSnapshot, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, type Uuid, version };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,23 @@
1
1
  import { Channel } from 'phoenix';
2
2
 
3
+ /**
4
+ * Hosted poolse API URL. Used as the default for `PoolseConfig.apiUrl`
5
+ * when you don't pass one — appropriate for the vast majority of
6
+ * integrations that target the official poolse cloud. Self-hosted /
7
+ * staging deployments override via the `apiUrl` field.
8
+ */
9
+ declare const POOLSE_API_URL = "https://api.poolse.dev";
3
10
  /**
4
11
  * SDK configuration passed to `new Poolse(config)`.
5
12
  */
6
13
  interface PoolseConfig {
7
14
  /**
8
- * Base URL of the poolse REST API, e.g. `https://chat.example.com`.
9
- * MUST NOT include the `/v1` path the SDK adds that itself.
15
+ * Base URL of the poolse REST API. Defaults to the hosted endpoint
16
+ * at `https://api.poolse.dev`. Override only for self-hosted /
17
+ * staging deployments. MUST NOT include the `/v1` path — the SDK
18
+ * adds that itself.
10
19
  */
11
- apiUrl: string;
20
+ apiUrl?: string;
12
21
  /**
13
22
  * Async hook the SDK calls every time it needs an `Authorization:
14
23
  * Bearer <jwt>` header. Most apps refresh the JWT from their own
@@ -146,6 +155,13 @@ interface Conversation {
146
155
  last_message_at: IsoDateTime | null;
147
156
  /** Monotonic per-conversation sequence counter (last message's `sequence`). */
148
157
  last_sequence: number;
158
+ /**
159
+ * Number of messages the caller hasn't read yet
160
+ * (`last_sequence - sequence_of(my_last_read_message_id)`).
161
+ * Populated only by `chat.conversations.list()` — undefined when the
162
+ * conversation is fetched via other paths.
163
+ */
164
+ unread_count?: number;
149
165
  inserted_at: IsoDateTime;
150
166
  updated_at: IsoDateTime;
151
167
  }
@@ -213,6 +229,13 @@ interface Message {
213
229
  thread_root_id: Uuid | null;
214
230
  mentions: Uuid[];
215
231
  reactions: Record<string, Uuid[]>;
232
+ /**
233
+ * Attachments linked to this message. Server populates on send +
234
+ * realtime broadcast; absent on partial responses (e.g. when the
235
+ * client posted with attachment_ids but the server has yet to
236
+ * resolve them).
237
+ */
238
+ attachments?: Attachment[];
216
239
  edited_at: IsoDateTime | null;
217
240
  deleted_at: IsoDateTime | null;
218
241
  sequence: number;
@@ -223,10 +246,31 @@ interface MessageList {
223
246
  data: Message[];
224
247
  }
225
248
  interface MessageCreateRequest {
226
- body: string;
249
+ /**
250
+ * Plain-text body. Optional only when `attachment_ids` is non-empty
251
+ * — a message with attachments AND no body is valid (just the
252
+ * attachment renders). At least one of `body` or `attachment_ids`
253
+ * must be present.
254
+ */
255
+ body?: string | null;
227
256
  type?: MessageType;
228
257
  reply_to_id?: Uuid;
229
258
  mentions?: Uuid[];
259
+ /**
260
+ * Attach previously-uploaded attachments to this message. Each id
261
+ * must come from `chat.attachments.upload(...)` or the lower-level
262
+ * `requestUpload(...)` flow and must belong to the same tenant.
263
+ * The server links them in the same transaction as the insert, so
264
+ * the broadcast and REST response both carry the resolved
265
+ * `Attachment` rows in `message.attachments`.
266
+ */
267
+ attachment_ids?: Uuid[];
268
+ /**
269
+ * Client-supplied UUID for retry-safe sends. The SDK fills this in
270
+ * automatically when not provided so the optimistic temp row and
271
+ * the canonical server row share a single id (used for id-based
272
+ * dedup in `useMessages`).
273
+ */
230
274
  id?: Uuid;
231
275
  }
232
276
  interface MessageUpdateRequest {
@@ -304,6 +348,18 @@ interface ReactionEvent {
304
348
  emoji: string;
305
349
  user_id: Uuid;
306
350
  }
351
+ /**
352
+ * `member:read` — a conversation member advanced their read cursor.
353
+ * Server broadcasts on `conversation:<id>` so the sender's
354
+ * read-receipt glyph (check vs check-double) updates in real time
355
+ * without needing to refetch the member list.
356
+ */
357
+ interface MemberReadEvent {
358
+ user_id: Uuid;
359
+ conversation_id: Uuid;
360
+ last_read_message_id: Uuid;
361
+ last_read_at: string;
362
+ }
307
363
  /** Per-user mention push on the `user:<id>` channel. */
308
364
  interface MentionEvent {
309
365
  message_id: Uuid;
@@ -421,6 +477,11 @@ declare class ConversationChannel {
421
477
  onTypingStop(fn: (evt: TypingEvent) => void): Unsubscribe;
422
478
  onReactionAdded(fn: (evt: ReactionEvent) => void): Unsubscribe;
423
479
  onReactionRemoved(fn: (evt: ReactionEvent) => void): Unsubscribe;
480
+ /**
481
+ * A conversation member advanced their read cursor. Used to flip the
482
+ * sender's read-receipt glyph from "sent" to "read" in real time.
483
+ */
484
+ onMemberRead(fn: (evt: MemberReadEvent) => void): Unsubscribe;
424
485
  onPresenceState(fn: (state: PresenceSnapshot) => void): Unsubscribe;
425
486
  onPresenceDiff(fn: (diff: PresenceSnapshot) => void): Unsubscribe;
426
487
  /** Send a typing ping to the server. Debounced server-side. */
@@ -772,4 +833,4 @@ declare class AuthError extends ApiError {
772
833
 
773
834
  declare const version = "0.0.1";
774
835
 
775
- export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, 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 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, type PoolseConfig, PoolseError, PoolseRealtime, type PresenceSnapshot, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, type Uuid, version };
836
+ export { type AddMemberOptions, ApiError, type Attachment, type AttachmentDownloadResponse, AttachmentHandle, type AttachmentOptions, 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 PresenceSnapshot, RateLimitedError, type ReactionEvent, type ReactionRequest, type ReadRequest, type RealtimeStatus, type TypingEvent, type Unsubscribe, UserChannel, type Uuid, version };
package/dist/index.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import { Socket } from 'phoenix';
2
2
 
3
3
  // src/config.ts
4
+ var POOLSE_API_URL = "https://api.poolse.dev";
4
5
  var DEFAULT_MAX_RETRIES = 3;
5
6
  var DEFAULT_BASE_BACKOFF_MS = 250;
6
7
  var DEFAULT_MAX_BACKOFF_MS = 3e4;
7
8
  function resolveConfig(config) {
8
- if (!config.apiUrl) {
9
- throw new Error("Poolse: `apiUrl` is required.");
10
- }
11
9
  if (typeof config.getToken !== "function") {
12
10
  throw new Error("Poolse: `getToken` is required and must be a function.");
13
11
  }
@@ -19,7 +17,7 @@ function resolveConfig(config) {
19
17
  }
20
18
  const fetchFn = rawFetch.bind(globalThis);
21
19
  return {
22
- apiUrl: trimTrailingSlash(config.apiUrl),
20
+ apiUrl: trimTrailingSlash(config.apiUrl ?? POOLSE_API_URL),
23
21
  getToken: config.getToken,
24
22
  fetch: fetchFn,
25
23
  maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
@@ -259,6 +257,13 @@ var ConversationChannel = class {
259
257
  onReactionRemoved(fn) {
260
258
  return this.subscribe("reaction:removed", fn);
261
259
  }
260
+ /**
261
+ * A conversation member advanced their read cursor. Used to flip the
262
+ * sender's read-receipt glyph from "sent" to "read" in real time.
263
+ */
264
+ onMemberRead(fn) {
265
+ return this.subscribe("member:read", fn);
266
+ }
262
267
  onPresenceState(fn) {
263
268
  return this.subscribe("presence_state", fn);
264
269
  }
@@ -741,6 +746,9 @@ var RestClient = class {
741
746
  if (opts.signal) init.signal = opts.signal;
742
747
  response = await this.config.fetch(url, init);
743
748
  } catch (err) {
749
+ if (err instanceof DOMException && err.name === "AbortError") {
750
+ throw err;
751
+ }
744
752
  if (attempt < maxRetries && isRetryableNetworkError(err)) {
745
753
  await sleep(this.backoffDelay(attempt));
746
754
  attempt += 1;
@@ -980,6 +988,6 @@ var Poolse = class {
980
988
  // src/version.ts
981
989
  var version = "0.0.1";
982
990
 
983
- export { ApiError, AttachmentHandle, AttachmentsResource, AuthError, ConversationChannel, ConversationHandle, ConversationMessages, ConversationsResource, MeResource, MessageHandle, MessagesResource, NetworkError, Poolse, PoolseError, PoolseRealtime, RateLimitedError, UserChannel, version };
991
+ export { ApiError, AttachmentHandle, AttachmentsResource, AuthError, ConversationChannel, ConversationHandle, ConversationMessages, ConversationsResource, MeResource, MessageHandle, MessagesResource, NetworkError, POOLSE_API_URL, Poolse, PoolseError, PoolseRealtime, RateLimitedError, UserChannel, version };
984
992
  //# sourceMappingURL=index.js.map
985
993
  //# sourceMappingURL=index.js.map