This commit is contained in:
Raven Scott
2026-05-20 23:36:32 -04:00
parent a020270cb1
commit be94546cd3
218 changed files with 9189 additions and 3078 deletions
@@ -2,84 +2,83 @@
**Protocol:** `document-line-lock/v1`
**Export:** `HyperP2PDocumentLineLock`
**Export:** `HyperP2PDocumentLineLock`, `PROTOCOL`
## Overview
Production p2p module: Hyperswarm discovery + Protomux when `topic` is set.
Optimistic line-level locks for collaborative documents. Locks are keyed `docId:line`; only the current holder may `release`. Remote peers learn locks via gossip.
## Constructor
```js
const mod = new HyperP2PDocumentLineLock(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | varies | null | topic |
| `keyPair` | KeyPair | random Ed25519 | keyPair |
| Option | Default | Description |
|--------|---------|-------------|
| `topic` | `null` | Swarm topic |
| `keyPair` | random | `holderHex` for acquire |
## Methods
### `acquire(docId, line)`
- **Returns:** `value`
- **Throws:** — (none documented in method body)
- **Returns:** `{ ok: true, docId, line, holder, at }` or `{ ok: false, holder }` if another peer holds the line
- **Gossip:** `{ type: 'line-lock', lock }`
- **Emits:** `acquire`
### `release(docId, line)`
- **Returns:** `value`
- **Throws:** — (none documented in method body)
- **Returns:** `boolean` — only true if this peer held the lock
- **Gossip:** `{ type: 'line-unlock', docId, line, holder }`
### `isLocked(docId, line)`
### `isLocked(docId, line)` / `getLock(docId, line)`
- **Returns:** `value`
- **Throws:** — (none documented in method body)
Query lock map.
### `getLock(docId, line)`
### `ready()` / `close()`
- **Returns:** `value`
- **Throws:** — (none documented in method body)
Swarm join/destroy.
### `getStats()`
### `getStats()`
- **Returns:** `object`
- **Throws:** — (none documented in method body)
`acquired`, `released`, `gossipIn`, `gossipOut`, `locks`, `protocol`.
### `ready(—)`
## Wire messages
- **Returns:** `Promise`
- **Throws:** — (none documented in method body)
### `close(—)`
- **Returns:** `Promise<void>`
- **Throws:** — (none documented in method body)
| type | payload |
|------|---------|
| `line-lock` | `lock` object |
| `line-unlock` | `docId`, `line`, `holder` |
## Events
| Event | Payload |
|-------|---------|
| `acquire` | lock |
| `release` | payload object |
| `remote-acquire` | data.lock |
| `remote-release` | data |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
`acquire`, `release`, `remote-acquire`, `remote-release`.
## Errors
Stable message substrings: see [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
`assertNonEmpty(docId)`.
## P2P
## Composition
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `document-line-lock/v1`.
`hyper-p2p-cursor-presence`, `hyper-p2p-collab-room`.
## Testing
```bash
npm install && npm test
```
`npm test`
## Example
`examples/basic.js`
## State model
Locks map `docId:line``{ holder, at }`. Conflicting acquire returns holder hex without throwing.
## Performance
O(1) acquire/release; gossip volume scales with edit churn.
## Versioning
`document-line-lock/v1` — add fields only in optional lock metadata later.
## See also
[`docs/architecture.md`](architecture.md)