@grayfalcon666/loom 1.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/README.md +161 -0
- package/embedded_wasm.js +5 -0
- package/index.js +137 -0
- package/loom.d.ts +139 -0
- package/loom.js +94 -0
- package/loom.wasm +0 -0
- package/package.json +48 -0
- package/wasm_exec.js +575 -0
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# @grayfalcon666/loom
|
|
2
|
+
|
|
3
|
+
A Go-powered CRDT engine for collaborative text editing, compiled to WebAssembly and running entirely in the browser — no backend required for the CRDT itself.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **RGA (Replicated Growable Array)** — character-level CRDT text editing with concurrent insert/delete support
|
|
8
|
+
- **LWW-Map** — key-value CRDT map
|
|
9
|
+
- **Zero-config init** — WASM is embedded as base64, `npm install` and go
|
|
10
|
+
- **Full TypeScript** type declarations included
|
|
11
|
+
- **Go + syscall/js** — all CRDT logic runs in the browser via WASM
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @grayfalcon666/loom
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { init } from '@grayfalcon666/loom';
|
|
23
|
+
|
|
24
|
+
const loom = await init(); // WASM loaded from embedded base64 — no extra files
|
|
25
|
+
|
|
26
|
+
const aliceDoc = loom.newDocument('alice');
|
|
27
|
+
const bobDoc = loom.newDocument('bob');
|
|
28
|
+
|
|
29
|
+
loom.addText(aliceDoc, 'body', 'shared-text');
|
|
30
|
+
|
|
31
|
+
// Alice inserts 'H' at position 0
|
|
32
|
+
const op = loom.insertChar(aliceDoc, 'shared-text', 0, 'H'.charCodeAt(0));
|
|
33
|
+
// Send op to your WebSocket server → peers receive it
|
|
34
|
+
|
|
35
|
+
// Bob applies the remote op
|
|
36
|
+
loom.unwrapReceive(bobDoc, op);
|
|
37
|
+
|
|
38
|
+
console.log(loom.peekText(bobDoc, 'shared-text')); // 'H'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## WebSocket Sync
|
|
42
|
+
|
|
43
|
+
`loom` does not include a WebSocket server. Any WS relay works. See the [server implementation](https://github.com/grayfalcon666/loom) for a reference Go backend.
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
const WS_URL = 'ws://localhost:8080/ws?doc=my-doc';
|
|
47
|
+
const ws = new WebSocket(WS_URL);
|
|
48
|
+
|
|
49
|
+
// Send local op to peers
|
|
50
|
+
ws.addEventListener('open', () => {
|
|
51
|
+
const op = loom.insertChar(doc, 'text-1', 0, 'X'.charCodeAt(0));
|
|
52
|
+
ws.send(op);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Apply remote op from peers
|
|
56
|
+
ws.addEventListener('message', (e) => {
|
|
57
|
+
loom.unwrapReceive(doc, e.data);
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API Reference
|
|
62
|
+
|
|
63
|
+
### `init(wasmUrl?)`
|
|
64
|
+
|
|
65
|
+
Initialize the WASM module.
|
|
66
|
+
|
|
67
|
+
- **No argument** (default): uses the embedded base64-encoded WASM. Zero network requests, no CORS issues.
|
|
68
|
+
- **`wasmUrl`**: load from a custom URL. Useful if you want to host `loom.wasm` yourself.
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// Zero-config
|
|
72
|
+
const loom = await init();
|
|
73
|
+
|
|
74
|
+
// Custom URL (e.g. from /slim export or CDN)
|
|
75
|
+
const loom = await init('https://cdn.example.com/loom.wasm');
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Document Management
|
|
79
|
+
|
|
80
|
+
| Method | Returns | Description |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `newDocument(actorID)` | `number` (docID) | Create a CRDT document |
|
|
83
|
+
| `freeDocument(docID)` | `void` | Free memory |
|
|
84
|
+
| `save(docID)` | `string` (JSON) | Serialize document |
|
|
85
|
+
| `load(snapshotJSON)` | `number` (new docID) | Load from snapshot |
|
|
86
|
+
| `getActorID(docID)` | `string` | Get actor ID |
|
|
87
|
+
|
|
88
|
+
### Text Editing
|
|
89
|
+
|
|
90
|
+
| Method | Returns | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `addText(docID, key, textObjID)` | `string` (Op JSON) | Declare shared text object |
|
|
93
|
+
| `insertChar(docID, textObjID, index, charCode)` | `string` (Op JSON) | Insert character |
|
|
94
|
+
| `deleteChar(docID, textObjID, index)` | `string` (Op JSON) | Delete character |
|
|
95
|
+
| `peekText(docID, textObjID)` | `string` | Get current text |
|
|
96
|
+
|
|
97
|
+
- `insertChar` / `deleteChar` return an **Op JSON string** — send this to your WebSocket server
|
|
98
|
+
- `addText` also returns an Op — call it on **all peers** before inserting
|
|
99
|
+
- `unwrapReceive(docID, opJSON)` applies a remote Op to a document
|
|
100
|
+
|
|
101
|
+
### LWW-Map
|
|
102
|
+
|
|
103
|
+
| Method | Returns | Description |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `set(docID, key, value)` | `string` (Op JSON) | Set key-value |
|
|
106
|
+
| `get(docID, key)` | `string` (JSON) | Get value |
|
|
107
|
+
|
|
108
|
+
## Package Structure
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
@grayfalcon666/loom/
|
|
112
|
+
├── index.js # Main entry — init() with embedded base64 WASM
|
|
113
|
+
├── loom.js # Raw JS wrapper (same as index.js but older API)
|
|
114
|
+
├── loom.d.ts # TypeScript declarations
|
|
115
|
+
├── loom.wasm # Raw .wasm binary (used if you pass url to init())
|
|
116
|
+
├── wasm_exec.js # Go WASM bootstrap (required by Go runtime)
|
|
117
|
+
└── embedded_wasm.js # AUTO-GENERATED: base64-encoded loom.wasm
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Saving / Loading
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
// Save to localStorage
|
|
124
|
+
localStorage.setItem('doc', loom.save(docID));
|
|
125
|
+
|
|
126
|
+
// Load on page refresh
|
|
127
|
+
const id = loom.load(localStorage.getItem('doc'));
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Subpath Exports
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// Full package (base64 WASM embedded — recommended)
|
|
134
|
+
import { init } from '@grayfalcon666/loom';
|
|
135
|
+
|
|
136
|
+
// Slim version — requires you to host loom.wasm separately
|
|
137
|
+
// (loom.wasm is ~3MB; slim skips the embedded base64 for smaller JS bundle)
|
|
138
|
+
import { init } from '@grayfalcon666/loom/slim';
|
|
139
|
+
const loom = await init('/node_modules/@grayfalcon666/loom/loom.wasm');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## TypeScript
|
|
143
|
+
|
|
144
|
+
Full TypeScript declarations are included. No `@types/` package needed.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { init, type LoomAPI } from '@grayfalcon666/loom';
|
|
148
|
+
|
|
149
|
+
const loom: LoomAPI = await init();
|
|
150
|
+
const docID: number = loom.newDocument('alice');
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Limitations
|
|
154
|
+
|
|
155
|
+
- `syscall/js` is the standard Go WASM path. Note that **Go has deprecated `syscall/js`** and the recommended future path is TinyGo + wasm-tools.
|
|
156
|
+
- This package is currently at **v1.0.0** — API is stabilizing but breaking changes are possible in minor releases until v2.
|
|
157
|
+
- The WASM is large (~3MB) because it includes the full Go runtime. Consider using the `/slim` export if bundle size matters.
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT
|