Skip to content

Share Policies

Share policies control who can sync a document. During P2P sync, getShared() checks the share policy before sending documents to a peer.

Structure

Set the share field when creating a document:

typescript
await store.add('bookmark', {
    uid,
    url: 'https://example.com',
    share: {
        public: { license: 'SRL' },
    }
});

Policy types

Public

Anyone can sync this document:

typescript
share: {
    public: { license: 'SRL' }
}

User-scoped

Only specific users can sync:

typescript
share: {
    users: {
        [aliceUidHex]: { license: 'SRL' },
        [bobUidHex]: { license: 'SRL' },
    }
}

Group-scoped

Members of a group can sync:

typescript
share: {
    groups: {
        [groupId]: { license: 'CC-BY' }
    }
}

Self (owner-only sync)

Sync only to the owner's own devices — personal data like read cursors, preferences, or draft content:

typescript
share: {
    self: true
}

This is the minimal share policy. The document syncs between the owner's phone, laptop, and tablet, but is never sent to other users.

Inherited

Inherit the share policy from the parent document. Use the literal string 'parent':

typescript
share: { ref: 'parent' }

The store resolves 'parent' at sync time, walking up to the document referenced by parent and applying its share policy. This is the canonical pattern for child documents (e.g. comments under a discussion).

Children with no share are local-only

If you create a document with parent set but no share field, it stays on the author's machine and never syncs — even if the parent's $child write rules allow it. There is no warning at write time; the peer simply never sees it.

Always set share: { ref: 'parent' } (or a more specific policy) on children that should follow the parent's sharing.

License types

LicenseDescription
'SRL'Standard Reason License — attribution, no commercial use
'CC-BY'Creative Commons Attribution
'PRIVATE'Private, no redistribution

Updating share policies

Share policies can be changed with edit():

typescript
await store.edit(uid, { hash }, {
    $set: {
        share: {
            users: {
                [newUserHex]: { license: 'SRL' }
            }
        }
    }
});

Whether a user can change the share policy depends on the document's write rules.

Custom share resolver

When the built-in policies aren't enough, provide a shareResolver callback on the DocumentStore constructor. It runs as a fallback — only called when none of the built-in policies (public, users, self, ref, membership tokens) granted access.

typescript
const store = new DocumentStore({
    storage,
    shareResolver: async (share, accessorUid, doc) => {
        // share: the document's share policy object
        // accessorUid: the peer requesting access (Buffer)
        // doc: the full rendered document

        // Example: identity docs are shared with contacts
        if (doc._type === 'identity') {
            return await isContact(doc.hash, accessorUid);
        }

        return false;
    },
});

When it's called

During sync, document-store evaluates access for each document in this order:

  1. Owner check (doc.hash === accessor or doc.uid === accessor)
  2. share.public
  3. share.users[accessor]
  4. Membership token matching
  5. shareResolver() — if all above denied access

Return true to grant access, false to deny.

Use cases

  • Contact-based sharing — share identity documents with all contacts without listing each one in share.users
  • Type-based sharing — share all documents of a certain type with specific peers
  • External data — check an external database or service to decide access

The callback receives the full rendered document, so it can inspect any field. It's async, so it can query databases or wish-core.

Performance

The resolver is called per document during sync access checks. Keep it fast — avoid expensive queries that don't cache well. For large-scale group access, prefer membership tokens instead.

No share policy

Documents without a share field are only stored locally. They won't be sent to peers during sync — not even to the owner's other devices. If you want private documents to sync across your own devices, use share: { self: true }.