js-bao-wss-client 2.2.0-alpha.2 → 2.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/README.md CHANGED
@@ -740,7 +740,7 @@ The client emits `documentMetadataChanged` whenever local metadata changes or se
740
740
  - Typical emissions:
741
741
  - **created/local**: immediately after `documents.create(...)` updates local cache. `changedFields` often includes `createdAt`, `pendingCreate`, `localOnly`, and optionally `title`.
742
742
  - **updated/local**: after local changes such as `documents.update(...)` (optimistic `title`), sync status updates (`lastSyncedAt`, `hasUnsyncedLocalChanges`), or localBytes refresh.
743
- - **updated/server**: after `documents.list({ refreshFromServer: true })` or network-first list merges server metadata (e.g., `title`, `permission`), `changedFields` reflects updated properties.
743
+ - **updated/server**: after `me.ownedDocuments({ refreshFromServer: true })` or network-first list merges server metadata (e.g., `title`, `permission`), `changedFields` reflects updated properties.
744
744
  - **evicted/local**: after `documents.evict(id)` or `documents.evictAll(...)`; `metadata` is `null`.
745
745
  - **deleted/server or local**: the first delete seen (server push, list refresh, or local `documents.delete`) emits a single `deleted` event; subsequent delete/evict/list refreshes for the same doc are suppressed to avoid duplicates (including 404/offline fallbacks after a successful delete).
746
746
 
@@ -810,11 +810,11 @@ await client.goOnline();
810
810
 
811
811
  ## Metadata Cache and Local Documents
812
812
 
813
- The client maintains an IndexedDB-backed metadata index so apps can render lists and document summaries offline. Local listing is merged into `documents.list(...)`; the former `documents.listLocal()` is removed.
813
+ The client maintains an IndexedDB-backed metadata index so apps can render lists and document summaries offline. Local listing is merged into `me.ownedDocuments(...)`; the former `documents.listLocal()` is removed.
814
814
 
815
815
  ```typescript
816
816
  // List documents (cache-first with background refresh by default)
817
- const docs = await client.documents.list({
817
+ const docs = await client.me.ownedDocuments({
818
818
  includeRoot: false,
819
819
  // Default behavior is cache-first with background refresh when local cache exists
820
820
  // You can control it explicitly with waitForLoad (see below)
@@ -841,7 +841,7 @@ client.setRetentionPolicy({
841
841
 
842
842
  Notes:
843
843
 
844
- - The client updates the local metadata cache automatically when `documents.list()` returns server data (including last-known permission and root doc metadata). Root is always cached from the server but filtered out of the returned list unless you pass `includeRoot: true`.
844
+ - The client updates the local metadata cache automatically when `me.ownedDocuments()` returns server data (including last-known permission and root doc metadata). Root is always cached from the server but filtered out of the returned list unless you pass `includeRoot: true`.
845
845
  - Cache updates emit `documentMetadataChanged` events (typically with `action: "updated"`, `source: "server"`).
846
846
  - Local eviction emits `documentMetadataChanged` with `action: "evicted"`, `metadata: null`.
847
847
  - Delete emits a single `documentMetadataChanged` with `action: "deleted"`, then evicts locally without a second emission.
@@ -900,19 +900,19 @@ Events: `pendingCreateCommitted`, `pendingCreateFailed` help drive UI state.
900
900
 
901
901
  ## Root Documents
902
902
 
903
- Some apps use a per-user root document. The server always returns the root in list responses (unless tag-filtered), and the client caches it. By default `documents.list()` filters it out; pass `includeRoot: true` to surface it (works offline after it’s cached).
903
+ Some apps use a per-user root document. The server always returns the root in list responses (unless tag-filtered), and the client caches it. By default `me.ownedDocuments()` filters it out; pass `includeRoot: true` to surface it (works offline after it’s cached).
904
904
 
905
905
  ```typescript
906
906
  // Exclude root (default)
907
- const docs = await client.documents.list();
907
+ const docs = await client.me.ownedDocuments();
908
908
 
909
909
  // Include root document(s)
910
- const all = await client.documents.list({ includeRoot: true });
910
+ const all = await client.me.ownedDocuments({ includeRoot: true });
911
911
  ```
912
912
 
913
913
  ## Behavior changes
914
914
 
915
- - **Root documents listing**: `documents.list()` excludes root docs by default. Opt-in with `{ includeRoot: true }`.
915
+ - **Root documents listing**: `me.ownedDocuments()` excludes root docs by default. Opt-in with `{ includeRoot: true }`.
916
916
  - **Offline mode requests**: When `networkMode` is `"offline"`, HTTP calls fail fast with code `OFFLINE`.
917
917
  - **Open options**: `documents.open()` uses `{ waitForLoad, enableNetworkSync, retainLocal, availabilityWaitMs }`. Older options like `waitForPermission`, `offlineWritePolicy`, per-doc `offline`, `provisionalPermission`, and `startNetwork` are removed.
918
918
  - **Create return shape**: `documents.create()` returns `{ metadata }` (no `Y.Doc`).
@@ -1160,8 +1160,11 @@ const { metadata } = await client.documents.create({
1160
1160
  });
1161
1161
  console.log("Created document:", metadata.documentId);
1162
1162
 
1163
- // List all documents user has access to
1164
- const documents = await client.documents.list();
1163
+ // List documents. There are two readers, and they are disjoint: the documents
1164
+ // the user owns, and the documents shared with them. Reading both is what it
1165
+ // takes to see everything the user has access to.
1166
+ const owned = await client.me.ownedDocuments(); // DocumentInfo[]
1167
+ const { items: shared } = await client.me.sharedDocuments(); // page 1 of { items, nextCursor }
1165
1168
 
1166
1169
  // Get document details (network)
1167
1170
  const docInfo = await client.documents.get(documentId);
@@ -1284,9 +1287,6 @@ await client.document(documentId).transferOwnership(newOwnerId);
1284
1287
  const accessResult = await client.documents.validateAccess(documentId);
1285
1288
  if (accessResult.hasAccess) {
1286
1289
  console.log("User has access:", accessResult.permission);
1287
- if (accessResult.viaInvitation) {
1288
- console.log("Access via invitation");
1289
- }
1290
1290
  }
1291
1291
  ```
1292
1292
 
@@ -1680,50 +1680,35 @@ function encodeRFC5987(value) {
1680
1680
 
1681
1681
  The canonical request uses only `origin + pathname`, so all disposition variants reuse the same cache entry. Metadata can live in memory (as shown) or in IndexedDB if you need to survive worker restarts. Because cached responses are stored without `Content-Disposition`, each hit reapplies headers based on the active request. Extend the sample with background eviction or cache versioning as needed.
1682
1682
 
1683
- ### Document Invitations
1684
-
1685
- ```typescript
1686
- // Create an invitation
1687
- const invitation = await client.documents.createInvitation(
1688
- documentId,
1689
- "user@example.com",
1690
- "read-write" // 'read-write' | 'reader'
1691
- );
1692
- console.log("Invitation created:", invitation.invitationId);
1683
+ ### Document Sharing
1693
1684
 
1694
- // List all invitations for a document
1695
- const invitations = await client.documents.listInvitations(documentId);
1685
+ Per-document invitations were removed in client `3.0.0`. Sharing is
1686
+ immediate: `updatePermissions` grants access to a registered user on the spot,
1687
+ and for an email that has not registered yet it writes a deferred grant plus an
1688
+ app-level invitation whose `inviteToken` the recipient redeems.
1696
1689
 
1697
- // Update an invitation (changes permission)
1698
- const updatedInvitation = await client.documents.updateInvitation(
1699
- documentId,
1700
- "user@example.com",
1701
- "reader"
1702
- );
1690
+ ```typescript
1691
+ // Share with an existing user (takes effect immediately) or defer the grant
1692
+ // for an email that has not registered yet.
1693
+ const grant = await client.documents.updatePermissions(documentId, {
1694
+ email: "user@example.com",
1695
+ permission: "read-write", // 'read-write' | 'reader'
1696
+ });
1697
+ if (grant.deferred) {
1698
+ console.log("Deferred until they accept:", grant.inviteToken);
1699
+ }
1703
1700
 
1704
- // Get specific invitation
1705
- const inv = await client.documents.getInvitation(
1706
- documentId,
1707
- "user@example.com"
1708
- );
1701
+ // Deferred grants still waiting on their recipient
1702
+ const pending = await client.documents.listPendingInvitations(documentId);
1709
1703
 
1710
- // Delete an invitation
1711
- await client.documents.deleteInvitation(documentId, invitationId);
1704
+ // Withdraw access (a live grant or a pending deferred one)
1705
+ await client.documents.removePermission(documentId, {
1706
+ email: "user@example.com",
1707
+ });
1712
1708
 
1713
- // Accept or decline (invitee)
1714
- await client.document(documentId).acceptInvitation();
1715
- await client.document(documentId).declineInvitation(invitationId);
1716
- ```
1717
-
1718
- ### Pending Document Invitations (for the current user)
1719
-
1720
- ```typescript
1721
- // List documents you’ve been invited to (pending, unexpired)
1722
- const pending = await client.me.pendingDocumentInvitations();
1723
- // Each item includes a best-effort `document` block with metadata (title, tags, createdAt, lastModified, createdBy)
1724
- for (const inv of pending) {
1725
- console.log(inv.document?.title, inv.document?.tags);
1726
- }
1709
+ // The recipient redeems the app-level invitation, which resolves every
1710
+ // deferred grant issued to their email.
1711
+ await client.invitations.accept(inviteToken);
1727
1712
  ```
1728
1713
 
1729
1714
  ### Users
@@ -1734,53 +1719,6 @@ const user = await client.users.getBasic("u01H...");
1734
1719
  console.log(user.name, user.email, user.appRole);
1735
1720
  ```
1736
1721
 
1737
- ### Invitation events
1738
-
1739
- The client emits a unified `invitation` event for real-time invitation changes delivered over the WebSocket. Payload:
1740
-
1741
- - `{ type: "invitation"; action: "created" | "updated" | "cancelled" | "declined" | "accepted"; invitationId; documentId; permission; title?; invitedBy?; invitedAt?; expiresAt?; acceptedBy?; document?: { title?; tags?; createdAt?; lastModified?; createdBy? } }`
1742
-
1743
- #### Actions — who receives each
1744
-
1745
- Events are **targeted**: most actions are delivered to only one side of the invitation (inviter _or_ invitee, not both). A consumer that only subscribes from the invitee side will never see `accepted`, and a consumer that only subscribes from the inviter side will never see `created`, `updated`, or `cancelled`. Both sides of the UI should handle the actions relevant to them.
1746
-
1747
- | `action` | Delivered to | When it fires |
1748
- | ------------ | --------------------- | ----------------------------------------------------------------------------- |
1749
- | `created` | **Invitee only** | A new pending invitation has been issued to this user. |
1750
- | `updated` | **Invitee only** | An existing pending invitation's permission / expiry was changed. |
1751
- | `cancelled` | **Invitee only** | The inviter (or an admin) cancelled a pending invitation before acceptance. |
1752
- | `declined` | **Invitee + inviter** | The invitee explicitly declined; both sides are notified. |
1753
- | `accepted` | **Inviter only** | The invitee accepted; `acceptedBy` carries the accepting user's `userId`. |
1754
-
1755
- Consumers writing a `switch` on `evt.action` should include a `default` branch that's either a no-op or a warning rather than throwing — new action values may be added in the future (non-breaking).
1756
-
1757
- Example:
1758
-
1759
- ```ts
1760
- client.on("invitation", (evt) => {
1761
- switch (evt.action) {
1762
- case "created":
1763
- case "updated":
1764
- case "cancelled":
1765
- // invitee-side: refresh pending-invitations list / badge
1766
- break;
1767
- case "declined":
1768
- // inviter-side: invite is no longer pending
1769
- break;
1770
- case "accepted":
1771
- // inviter-side: new collaborator
1772
- console.log(`${evt.acceptedBy} accepted invitation to ${evt.documentId}`);
1773
- break;
1774
- default:
1775
- // Unknown action — log and ignore rather than throw, so the client
1776
- // stays forward-compatible if new action values are added later.
1777
- console.warn("Unknown invitation action", evt);
1778
- }
1779
- });
1780
- ```
1781
-
1782
- Use this to refresh invitation lists or badge counts without polling.
1783
-
1784
1722
  ## Large Language Models (LLM)
1785
1723
 
1786
1724
  > **Deprecated.** The direct LLM client API (`client.llm.*`) is deprecated and will be removed in a future major release. Use managed prompts (`client.prompts.execute`) or a workflow `llm.chat` step instead.
@@ -3485,13 +3423,12 @@ class CollaborativeEditor {
3485
3423
  permission: "read-write" | "reader"
3486
3424
  ) {
3487
3425
  try {
3488
- const invitation = await this.client.documents.createInvitation(
3489
- documentId,
3426
+ const grant = await this.client.documents.updatePermissions(documentId, {
3490
3427
  email,
3491
- permission
3492
- );
3493
- console.log("Invitation sent:", invitation.invitationId);
3494
- return invitation;
3428
+ permission,
3429
+ });
3430
+ console.log("Shared with", email, grant);
3431
+ return grant;
3495
3432
  } catch (error) {
3496
3433
  console.error("Failed to invite user:", error);
3497
3434
  throw error;
@@ -37,7 +37,7 @@ export { JsBaoError, isJsBaoError, LockTimeoutError, JsBaoApiError, isJsBaoApiEr
37
37
  export type { JsBaoErrorCode } from "./errors";
38
38
  export { AuthError, AUTH_CODES, googleWebClientAvailable, } from "./internal/authController";
39
39
  export type { AuthCode, GoogleClientConfig, GoogleClientsConfig, } from "./internal/authController";
40
- export type { DocumentInfo, DocumentPermissionEntry, DocumentInvitation, DocumentInvitationResponse, DocumentAccessResult, DocumentGroupPermissionEntry, DocumentAliasInfo, DocumentAliasScope, PermissionUpdateResult, DirectPermissionGrant, DeferredPermissionGrant, PendingInvitationEntry, PendingGroupInvitationEntry, LinkAccessResult, } from "./api/documentsApi";
40
+ export type { DocumentInfo, DocumentPermissionEntry, DocumentAccessResult, DocumentGroupPermissionEntry, DocumentAliasInfo, DocumentAliasScope, PermissionUpdateResult, DirectPermissionGrant, DeferredPermissionGrant, PendingInvitationEntry, PendingGroupInvitationEntry, LinkAccessResult, } from "./api/documentsApi";
41
41
  export type { UserProfile, SharedDocument, SharedDocumentListResult, SharedDocumentsOptions, OwnedDocumentsOptions, } from "./api/meApi";
42
42
  export type { SessionInfo } from "./api/sessionApi";
43
43
  export type { BasicUserInfo, BatchUserProfile } from "./api/usersApi";
@@ -93,7 +93,7 @@ export type { DocumentDebugSnapshot, DocumentPermission, LocalDocumentEntry, Loc
93
93
  export type { LogLevel } from "./internal/logger";
94
94
  export type { RequestOptions } from "./internal/httpClient";
95
95
  export type { LocksAPI } from "./api/locksApi";
96
- export type { FunctionsAPI, FunctionInvokeOptions, FunctionInvokeResult, FunctionInvokeStatus, } from "./api/functionsApi";
96
+ export type { FunctionsAPI, FunctionInvokeOptions, FunctionInvokeResult, FunctionInvokeStatus, FunctionStartOptions, FunctionStartResult, FunctionRunRef, } from "./api/functionsApi";
97
97
  export type { LockHandle, LockContention, AcquireResponse, AcquireOptions, BlockingAcquireOptions, ReleaseResult, RenewResult, LockStatus, LockListEntry, LockListResult, } from "./api/locksApi";
98
98
  export type { ResourceMetadataAPI } from "./api/resourceMetadataApi";
99
99
  export type { ResourceMetadataReadResult, ResourceMetadataWriteResult, ResourceMetadataBatchRequestItem, ResourceMetadataBatchParams, ResourceMetadataBatchCategoryResult, ResourceMetadataBatchResourceResult, ResourceMetadataBatchResult, ResourceMetadataListEntry, ResourceMetadataListResult, ResourceMetadataDeleteResult, ResourceMetadataResolveParams, ResourceMetadataResolveResult, } from "./api/resourceMetadataApi";
@@ -865,64 +865,24 @@ export interface NotificationEvent {
865
865
  createdAt: string;
866
866
  }
867
867
  /**
868
- * Real-time notification that a document invitation has changed state.
868
+ * A message a server function sent to this user or this connection.
869
869
  *
870
- * Emitted over the `invitation` event channel (`client.on("invitation", ...)`).
870
+ * Emitted over the `directMessage` event channel
871
+ * (`client.on("directMessage", ...)`) when a function calls `ctx.users.send`
872
+ * or `ctx.connections.send` while this client is connected. `payload` is the
873
+ * function's own value, passed through unread by the platform.
871
874
  *
872
- * **Important:** events are targeted most actions are delivered to only one
873
- * side of the invitation (inviter _or_ invitee, not both). Consumers must
874
- * write a switch that handles every action value, or they will silently drop
875
- * events. See {@link InvitationEvent.action} for the full list and who
876
- * receives each.
875
+ * It is a LIVE frame with no durable record behind it: a client that was
876
+ * offline when the function ran does not receive it later. `functionKey` is
877
+ * the frame's only attribution a function running in system mode acts for
878
+ * nobody, so there is no user to name.
877
879
  */
878
- export interface InvitationEvent {
879
- type: "invitation";
880
- /**
881
- * The lifecycle transition that just occurred for this invitation.
882
- *
883
- * **Targeting (who receives each action — note the asymmetry):**
884
- *
885
- * - `"created"` — sent to the **invitee only**. A new invitation has been
886
- * sent to them; their UI should surface it.
887
- * - `"updated"` — sent to the **invitee only**. An existing pending
888
- * invitation was changed (e.g. permission re-issued /
889
- * expiry extended).
890
- * - `"cancelled"` — sent to the **invitee only**. The inviter (or an admin)
891
- * cancelled the pending invitation; the invitee's UI
892
- * should drop it from their pending list.
893
- * - `"declined"` — sent to **both the invitee and the inviter**. The
894
- * invitee explicitly declined; both sides' UIs should
895
- * update (invitee removes from pending, inviter sees the
896
- * outcome).
897
- * - `"accepted"` — sent to the **inviter only**. The invitee accepted and
898
- * now holds a `DocumentPermission`; the inviter's UI can
899
- * update collaborator lists. `acceptedBy` carries the
900
- * accepting user's `userId`.
901
- *
902
- * New action values may be added in the future (non-breaking); consumer
903
- * switches should include a `default` branch that is either a no-op or a
904
- * warning rather than throwing.
905
- */
906
- action: "created" | "updated" | "cancelled" | "declined" | "accepted";
907
- invitationId: string;
908
- documentId: string;
909
- permission: string;
910
- title?: string;
911
- invitedBy?: string;
912
- invitedAt?: string;
913
- expiresAt?: string;
914
- /**
915
- * UserId of the invitee who accepted. Populated only when `action === "accepted"`.
916
- */
917
- acceptedBy?: string;
918
- document?: {
919
- documentId?: string;
920
- title?: string;
921
- tags?: string[];
922
- createdAt?: string;
923
- lastModified?: string;
924
- createdBy?: string;
925
- };
880
+ export interface DirectMessageEvent {
881
+ type: "direct.message";
882
+ payload: unknown;
883
+ functionKey: string;
884
+ /** When the platform sent it, ISO 8601. */
885
+ sentAt: string;
926
886
  }
927
887
  /**
928
888
  * Payload of the `workflowStatus` event (`client.on("workflowStatus", ...)`).
@@ -1600,8 +1560,8 @@ export interface JsBaoEvents {
1600
1560
  pendingCreateFailed: PendingCreateFailedEvent;
1601
1561
  meUpdated: MeUpdatedEvent;
1602
1562
  meUpdateFailed: MeUpdateFailedEvent;
1603
- invitation: InvitationEvent;
1604
1563
  notification: NotificationEvent;
1564
+ directMessage: DirectMessageEvent;
1605
1565
  workflowStatus: WorkflowStatusEvent;
1606
1566
  workflowStarted: WorkflowStartedEvent;
1607
1567
  syncPerf: {
@@ -2900,8 +2860,8 @@ export declare class JsBaoClient extends Observable<any> {
2900
2860
  private handlePendingCreateCommitted;
2901
2861
  private handlePendingCreateFailed;
2902
2862
  private handleDocumentMetadataUpdate;
2903
- private handleInvitationMessage;
2904
2863
  private handleNotificationMessage;
2864
+ private handleDirectMessage;
2905
2865
  private handleWorkflowStatusMessage;
2906
2866
  private handleWorkflowStartedMessage;
2907
2867
  private handleOfflineAuthMessage;
@@ -3714,9 +3674,11 @@ export declare class JsBaoClient extends Observable<any> {
3714
3674
  ttlMs?: number;
3715
3675
  preserveOnSignOut?: boolean;
3716
3676
  }): void;
3717
- /** Create a new document. Writable locally immediately, with the server
3677
+ /** Create a new document. Writes local metadata only, with the server
3718
3678
  * commit racing in the background — unless `options.localOnly` is set, in
3719
- * which case the document never syncs.
3679
+ * which case the document never syncs. The document is NOT opened: call
3680
+ * `documents.open(documentId)` before reading or writing it, or the write
3681
+ * throws "Document `<id>` is not open".
3720
3682
  * @param options - Document creation options
3721
3683
  * @group Documents */
3722
3684
  createDocument(options: CreateDocumentOptions): Promise<{