@poolse/sdk 1.1.0 → 2.0.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.
- package/CHANGELOG.md +42 -0
- package/README.md +3 -1
- package/dist/index.cjs +31 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -21
- package/dist/index.d.ts +44 -21
- package/dist/index.js +31 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,48 @@ All notable changes to `@poolse/sdk` are documented here. Format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
|
|
5
5
|
[semver](https://semver.org).
|
|
6
6
|
|
|
7
|
+
## [2.0.0] — 2026-06-03
|
|
8
|
+
|
|
9
|
+
Lockstep release with `@poolse/react@2.0.0` and `@poolse/react-ui@2.0.0`.
|
|
10
|
+
Single load-bearing change: the SDK no longer surfaces poolse-internal
|
|
11
|
+
user uuids in identity-shaped APIs — everything is keyed by the
|
|
12
|
+
tenant's own `external_id` instead.
|
|
13
|
+
|
|
14
|
+
### Breaking
|
|
15
|
+
|
|
16
|
+
- **`PoolseConfig.userResolver` signature changes.** Was
|
|
17
|
+
`(userId: string) => UserProfile | null`; now
|
|
18
|
+
`(externalId: string) => UserProfile | null`. Your resolver receives
|
|
19
|
+
YOUR user id (the same string you pass when minting JWTs and as
|
|
20
|
+
`member_external_ids`), so no `poolse_user_id` column is needed.
|
|
21
|
+
- **`Message.sender_external_id`** added (string | null, required on
|
|
22
|
+
every wire payload that carries a sender).
|
|
23
|
+
- **`Membership.external_id`** added (string, required).
|
|
24
|
+
- **`QuotedMessagePreview.sender_external_id`** added.
|
|
25
|
+
- **`TypingEvent.external_id`** added — `useTyping` returns
|
|
26
|
+
`Set<externalId>` instead of `Set<userId>`.
|
|
27
|
+
- **`UsersResource.{peek, get, subscribe, invalidate}`** all keyed by
|
|
28
|
+
`externalId` (was `userId`). Same semantics; same caching.
|
|
29
|
+
|
|
30
|
+
### Migration
|
|
31
|
+
|
|
32
|
+
See `MIGRATING.md` at the repo root. For most apps it's a rename of
|
|
33
|
+
the resolver argument plus deleting the `poolse_user_id` column if
|
|
34
|
+
you stored one.
|
|
35
|
+
|
|
36
|
+
### Backend coupling
|
|
37
|
+
|
|
38
|
+
Pairs with the `poolse-server` change that:
|
|
39
|
+
- lazy-provisions unknown `external_id`s referenced in
|
|
40
|
+
`POST /v1/conversations` (`member_external_ids`) and
|
|
41
|
+
`POST /v1/conversations/:id/members` (`external_ids`), abuse-capped
|
|
42
|
+
at 50/hour per JWT,
|
|
43
|
+
- emits `sender_external_id` / `external_id` on every user-shaped
|
|
44
|
+
wire payload (REST, webhook, realtime).
|
|
45
|
+
|
|
46
|
+
Self-hosted `@poolse/sdk@2.0.0` against an older backend will get
|
|
47
|
+
`sender_external_id: null` everywhere — degraded display, but no crash.
|
|
48
|
+
|
|
7
49
|
## [1.1.0] — 2026-06-02
|
|
8
50
|
|
|
9
51
|
Lockstep release with `@poolse/react@1.1.0` and `@poolse/react-ui@1.1.0`.
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Headless TypeScript SDK for [poolse](https://poolse.dev) — REST + WebSocket cl
|
|
|
4
4
|
|
|
5
5
|
If you're using React, you'll usually want [`@poolse/react`](https://www.npmjs.com/package/@poolse/react) (hooks) or [`@poolse/react-ui`](https://www.npmjs.com/package/@poolse/react-ui) (prebuilt chat surface). Both sit on top of this package; you can drop down to it whenever you outgrow them.
|
|
6
6
|
|
|
7
|
+
> **⚠️ Upgrading from 1.x?** See [MIGRATING.md](https://github.com/poolse-hq/js-sdk/blob/main/MIGRATING.md). 2.0 is a breaking change: identity APIs are now keyed by your `external_id` instead of poolse uuids — `userResolver`, `useUser`, member operations all flip.
|
|
8
|
+
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
@@ -73,7 +75,7 @@ chat.destroy(); // closes WebSocket, leaves every joined channel
|
|
|
73
75
|
| `maxBackoffMs` | `number` | `30000` | Hard ceiling on a single retry delay. |
|
|
74
76
|
| `generateIdempotencyKey` | `() => string` | `crypto.randomUUID()` | Override the key generator. Defaults throws at construction time if no `crypto.randomUUID` is available. |
|
|
75
77
|
| `onSocketError` | `(err: Error) => void` | — | Fired on non-fatal socket errors (Phoenix handles reconnect internally; this is for surface-level banners). |
|
|
76
|
-
| `userResolver` | `(
|
|
78
|
+
| `userResolver` | `(externalId: string) => Promise<PoolseUserProfile \| null> \| PoolseUserProfile \| null` | — | Optional. Resolve the tenant's own user identifier (`external_id` — same string you pass when minting JWTs) to `{ displayName, avatarUrl }` from your app's user data. The UI packages pick this up automatically. |
|
|
77
79
|
|
|
78
80
|
## REST surface
|
|
79
81
|
|
package/dist/index.cjs
CHANGED
|
@@ -815,55 +815,55 @@ var UsersResource = class {
|
|
|
815
815
|
* "not in cache yet" (different from `null`, which means "resolver
|
|
816
816
|
* ran and the user wasn't found").
|
|
817
817
|
*/
|
|
818
|
-
peek(
|
|
819
|
-
return this.cache.get(
|
|
818
|
+
peek(externalId) {
|
|
819
|
+
return this.cache.get(externalId);
|
|
820
820
|
}
|
|
821
821
|
/**
|
|
822
822
|
* Resolve a user, hitting the customer's `userResolver` on cache
|
|
823
|
-
* miss. Concurrent calls for the same
|
|
823
|
+
* miss. Concurrent calls for the same external_id share one Promise.
|
|
824
824
|
*/
|
|
825
|
-
async get(
|
|
826
|
-
if (this.cache.has(
|
|
827
|
-
return this.cache.get(
|
|
825
|
+
async get(externalId) {
|
|
826
|
+
if (this.cache.has(externalId)) {
|
|
827
|
+
return this.cache.get(externalId) ?? null;
|
|
828
828
|
}
|
|
829
|
-
const existingPending = this.pending.get(
|
|
829
|
+
const existingPending = this.pending.get(externalId);
|
|
830
830
|
if (existingPending) return existingPending;
|
|
831
831
|
const resolver = this.config.userResolver;
|
|
832
832
|
if (!resolver) {
|
|
833
|
-
this.cache.set(
|
|
834
|
-
this.notify(
|
|
833
|
+
this.cache.set(externalId, null);
|
|
834
|
+
this.notify(externalId);
|
|
835
835
|
return null;
|
|
836
836
|
}
|
|
837
|
-
const promise = Promise.resolve().then(() => resolver(
|
|
837
|
+
const promise = Promise.resolve().then(() => resolver(externalId)).then(
|
|
838
838
|
(profile) => {
|
|
839
|
-
this.cache.set(
|
|
840
|
-
this.pending.delete(
|
|
841
|
-
this.notify(
|
|
839
|
+
this.cache.set(externalId, profile ?? null);
|
|
840
|
+
this.pending.delete(externalId);
|
|
841
|
+
this.notify(externalId);
|
|
842
842
|
return profile ?? null;
|
|
843
843
|
},
|
|
844
844
|
(err) => {
|
|
845
|
-
console.error("[poolse] userResolver failed for",
|
|
846
|
-
this.cache.set(
|
|
847
|
-
this.pending.delete(
|
|
848
|
-
this.notify(
|
|
845
|
+
console.error("[poolse] userResolver failed for", externalId, err);
|
|
846
|
+
this.cache.set(externalId, null);
|
|
847
|
+
this.pending.delete(externalId);
|
|
848
|
+
this.notify(externalId);
|
|
849
849
|
return null;
|
|
850
850
|
}
|
|
851
851
|
);
|
|
852
|
-
this.pending.set(
|
|
852
|
+
this.pending.set(externalId, promise);
|
|
853
853
|
return promise;
|
|
854
854
|
}
|
|
855
855
|
/**
|
|
856
|
-
* Subscribe to changes for a single
|
|
856
|
+
* Subscribe to changes for a single external_id. The listener fires
|
|
857
857
|
* when the resolver lands (or when the entry is invalidated).
|
|
858
858
|
* Returns an unsubscribe.
|
|
859
859
|
*
|
|
860
860
|
* `useUser` in @poolse/react uses this with `useSyncExternalStore`.
|
|
861
861
|
*/
|
|
862
|
-
subscribe(
|
|
863
|
-
let set = this.listeners.get(
|
|
862
|
+
subscribe(externalId, listener) {
|
|
863
|
+
let set = this.listeners.get(externalId);
|
|
864
864
|
if (!set) {
|
|
865
865
|
set = /* @__PURE__ */ new Set();
|
|
866
|
-
this.listeners.set(
|
|
866
|
+
this.listeners.set(externalId, set);
|
|
867
867
|
}
|
|
868
868
|
set.add(listener);
|
|
869
869
|
return () => {
|
|
@@ -871,10 +871,10 @@ var UsersResource = class {
|
|
|
871
871
|
};
|
|
872
872
|
}
|
|
873
873
|
/** Drop a single cached entry — next `get` re-fetches via the resolver. */
|
|
874
|
-
invalidate(
|
|
875
|
-
this.cache.delete(
|
|
876
|
-
this.pending.delete(
|
|
877
|
-
this.notify(
|
|
874
|
+
invalidate(externalId) {
|
|
875
|
+
this.cache.delete(externalId);
|
|
876
|
+
this.pending.delete(externalId);
|
|
877
|
+
this.notify(externalId);
|
|
878
878
|
}
|
|
879
879
|
/**
|
|
880
880
|
* Drop the entire cache. Use after a sign-out, tenant swap, or any
|
|
@@ -884,12 +884,12 @@ var UsersResource = class {
|
|
|
884
884
|
invalidateAll() {
|
|
885
885
|
this.cache.clear();
|
|
886
886
|
this.pending.clear();
|
|
887
|
-
for (const
|
|
888
|
-
this.notify(
|
|
887
|
+
for (const externalId of this.listeners.keys()) {
|
|
888
|
+
this.notify(externalId);
|
|
889
889
|
}
|
|
890
890
|
}
|
|
891
|
-
notify(
|
|
892
|
-
const set = this.listeners.get(
|
|
891
|
+
notify(externalId) {
|
|
892
|
+
const set = this.listeners.get(externalId);
|
|
893
893
|
if (!set) return;
|
|
894
894
|
for (const l of set) l();
|
|
895
895
|
}
|
|
@@ -1172,7 +1172,7 @@ var Poolse = class {
|
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
1174
|
// src/version.ts
|
|
1175
|
-
var version = "
|
|
1175
|
+
var version = "2.0.0";
|
|
1176
1176
|
|
|
1177
1177
|
exports.ApiError = ApiError;
|
|
1178
1178
|
exports.AttachmentHandle = AttachmentHandle;
|