@automerge/automerge-repo-svelte-store 2.0.0-beta.5 → 2.0.0-beta.6
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 +175 -25
- package/dist/index.d.ts +53 -0
- package/dist/index.js +112 -0
- package/package.json +21 -7
- package/src/lib/index.ts +175 -0
- package/src/index.ts +0 -102
- package/tsconfig.json +0 -16
- package/typedoc.json +0 -5
package/README.md
CHANGED
|
@@ -1,54 +1,204 @@
|
|
|
1
1
|
# Svelte store for Automerge Repo
|
|
2
2
|
|
|
3
|
+
A reactive Svelte store for Automerge documents. Compatible with Svelte 3, 4, and 5.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @automerge/automerge-repo-svelte-store
|
|
9
|
+
```
|
|
10
|
+
|
|
3
11
|
## Example Usage
|
|
4
12
|
|
|
5
|
-
|
|
13
|
+
### Basic Usage
|
|
14
|
+
|
|
15
|
+
```svelte
|
|
16
|
+
<script>
|
|
17
|
+
import { Repo } from "@automerge/automerge-repo"
|
|
18
|
+
import { createAutomergeStore } from "@automerge/automerge-repo-svelte-store"
|
|
6
19
|
|
|
7
|
-
|
|
20
|
+
// Create a repo
|
|
21
|
+
const repo = new Repo({
|
|
22
|
+
// Configuration...
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Create a store from the repo
|
|
26
|
+
const automergeStore = createAutomergeStore(repo)
|
|
27
|
+
|
|
28
|
+
// Load or create a document
|
|
29
|
+
let documentStore = null
|
|
30
|
+
|
|
31
|
+
async function loadDocument(url) {
|
|
32
|
+
documentStore = await automergeStore.find(url)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function createDocument() {
|
|
36
|
+
documentStore = await automergeStore.create({ count: 0 })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Update the document
|
|
40
|
+
function incrementCounter() {
|
|
41
|
+
if (documentStore) {
|
|
42
|
+
documentStore.change(doc => {
|
|
43
|
+
doc.count = (doc.count || 0) + 1
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Using with Svelte Context (recommended)
|
|
8
51
|
|
|
9
52
|
```svelte
|
|
10
|
-
|
|
53
|
+
<!-- App.svelte -->
|
|
54
|
+
<script>
|
|
11
55
|
import { Repo } from "@automerge/automerge-repo"
|
|
12
|
-
import Counter from './lib/Counter.svelte'
|
|
13
56
|
import { setContextRepo } from "@automerge/automerge-repo-svelte-store"
|
|
57
|
+
import Counter from './Counter.svelte'
|
|
14
58
|
|
|
15
|
-
const repo = new Repo({
|
|
59
|
+
const repo = new Repo({
|
|
60
|
+
// Configuration...
|
|
61
|
+
})
|
|
16
62
|
|
|
17
|
-
// Make
|
|
63
|
+
// Make repo available to child components
|
|
18
64
|
setContextRepo(repo)
|
|
19
65
|
|
|
20
|
-
|
|
66
|
+
// Create a document asynchronously
|
|
67
|
+
let docUrl = null
|
|
68
|
+
|
|
69
|
+
async function setupDoc() {
|
|
70
|
+
const handle = await repo.create({ count: 0 })
|
|
71
|
+
docUrl = handle.url
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
setupDoc()
|
|
21
75
|
</script>
|
|
22
76
|
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
77
|
+
{#if docUrl}
|
|
78
|
+
<Counter {docUrl} />
|
|
79
|
+
{:else}
|
|
80
|
+
<p>Creating document...</p>
|
|
81
|
+
{/if}
|
|
28
82
|
```
|
|
29
83
|
|
|
30
|
-
|
|
84
|
+
```svelte
|
|
85
|
+
<!-- Counter.svelte -->
|
|
86
|
+
<script>
|
|
87
|
+
import { document } from "@automerge/automerge-repo-svelte-store"
|
|
88
|
+
import { onMount } from "svelte"
|
|
89
|
+
|
|
90
|
+
export let docUrl
|
|
91
|
+
|
|
92
|
+
// The document store - initially null
|
|
93
|
+
let docStore = null
|
|
94
|
+
|
|
95
|
+
// Load the document on mount
|
|
96
|
+
onMount(async () => {
|
|
97
|
+
// document() is async and returns a Promise
|
|
98
|
+
docStore = await document(docUrl)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
function increment() {
|
|
102
|
+
if (!docStore) return
|
|
103
|
+
|
|
104
|
+
// Access the document using the Svelte store $ syntax
|
|
105
|
+
docStore.change(doc => {
|
|
106
|
+
doc.count = (doc.count || 0) + 1
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
{#if docStore}
|
|
112
|
+
<button on:click={increment}>
|
|
113
|
+
Count: {$docStore.count || 0}
|
|
114
|
+
</button>
|
|
115
|
+
{:else}
|
|
116
|
+
<p>Loading document...</p>
|
|
117
|
+
{/if}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Using with Svelte 5 Runes
|
|
121
|
+
|
|
122
|
+
With Svelte 5, you can use the store with runes syntax for a more ergonomic experience:
|
|
31
123
|
|
|
32
124
|
```svelte
|
|
33
|
-
<script
|
|
34
|
-
import type { DocumentId } from "@automerge/automerge-repo"
|
|
125
|
+
<script>
|
|
35
126
|
import { document } from "@automerge/automerge-repo-svelte-store"
|
|
36
127
|
|
|
37
|
-
export let
|
|
128
|
+
export let docUrl
|
|
129
|
+
|
|
130
|
+
// Initialize state
|
|
131
|
+
let docStore = $state(null)
|
|
132
|
+
let loading = $state(true)
|
|
133
|
+
let error = $state(null)
|
|
134
|
+
let count = $derived(docStore?.$doc?.count || 0)
|
|
135
|
+
|
|
136
|
+
// Load document when component initializes
|
|
137
|
+
$effect(() => {
|
|
138
|
+
async function loadDocument() {
|
|
139
|
+
try {
|
|
140
|
+
loading = true
|
|
141
|
+
docStore = await document(docUrl)
|
|
142
|
+
loading = false
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.error("Failed to load document:", err)
|
|
145
|
+
error = err
|
|
146
|
+
loading = false
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
loadDocument()
|
|
151
|
+
})
|
|
38
152
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
153
|
+
function increment() {
|
|
154
|
+
if (docStore) {
|
|
155
|
+
docStore.change(doc => {
|
|
156
|
+
doc.count = (doc.count || 0) + 1
|
|
157
|
+
})
|
|
158
|
+
}
|
|
44
159
|
}
|
|
45
160
|
</script>
|
|
46
161
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
162
|
+
{#if loading}
|
|
163
|
+
<p>Loading document...</p>
|
|
164
|
+
{:else if error}
|
|
165
|
+
<p>Error: {error.message}</p>
|
|
166
|
+
{:else}
|
|
167
|
+
<button on:click={increment}>
|
|
168
|
+
Count: {count}
|
|
169
|
+
</button>
|
|
170
|
+
{/if}
|
|
50
171
|
```
|
|
51
172
|
|
|
173
|
+
## API Reference
|
|
174
|
+
|
|
175
|
+
### `createAutomergeStore(repo)`
|
|
176
|
+
|
|
177
|
+
Creates an Automerge store factory from a repo instance.
|
|
178
|
+
|
|
179
|
+
### `setContextRepo(repo)`
|
|
180
|
+
|
|
181
|
+
Sets the Automerge repo in the current component's context.
|
|
182
|
+
|
|
183
|
+
### `getContextRepo()`
|
|
184
|
+
|
|
185
|
+
Gets the Automerge repo from the current component's context.
|
|
186
|
+
|
|
187
|
+
### `document(docIdOrUrl, repoInstance?)`
|
|
188
|
+
|
|
189
|
+
Convenience method to load a document from the repo in context or a provided repo.
|
|
190
|
+
**Important:** This function returns a Promise that resolves to the document store.
|
|
191
|
+
|
|
192
|
+
## Store API
|
|
193
|
+
|
|
194
|
+
The document store returned by `find()` and `create()` implements Svelte's writable store contract with these additional methods:
|
|
195
|
+
|
|
196
|
+
- `change(fn)`: Make changes to the document
|
|
197
|
+
- `url`: Get the document URL
|
|
198
|
+
- `documentId`: Get the document ID
|
|
199
|
+
- `handle`: Access the underlying Automerge document handle
|
|
200
|
+
|
|
52
201
|
## Contributors
|
|
53
202
|
|
|
54
|
-
Originally written by Dylan MacKenzie (
|
|
203
|
+
Originally written by Dylan MacKenzie (@ecstatic-morse).
|
|
204
|
+
Updated for Svelte 5 compatibility by the Automerge team.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AutomergeUrl, ChangeFn, Doc, DocHandle, DocumentId, Repo } from "@automerge/automerge-repo/slim";
|
|
2
|
+
import { type Writable } from "svelte/store";
|
|
3
|
+
/**
|
|
4
|
+
* Set the Automerge Repo in the Svelte context
|
|
5
|
+
* @param repo The Automerge Repo instance
|
|
6
|
+
*/
|
|
7
|
+
export declare function setContextRepo(repo: Repo): void;
|
|
8
|
+
/**
|
|
9
|
+
* Get the Automerge Repo from the Svelte context
|
|
10
|
+
* @returns The Automerge Repo instance
|
|
11
|
+
*/
|
|
12
|
+
export declare function getContextRepo(): Repo;
|
|
13
|
+
/**
|
|
14
|
+
* The Automerge document store interface
|
|
15
|
+
*/
|
|
16
|
+
export interface AutomergeDocumentStore<T> extends Writable<Doc<T> | null> {
|
|
17
|
+
/**
|
|
18
|
+
* Make changes to the document
|
|
19
|
+
* @param changeFn Function that modifies the document
|
|
20
|
+
*/
|
|
21
|
+
change(changeFn: ChangeFn<T>): void;
|
|
22
|
+
/**
|
|
23
|
+
* The URL of the document
|
|
24
|
+
*/
|
|
25
|
+
readonly url: AutomergeUrl;
|
|
26
|
+
/**
|
|
27
|
+
* The ID of the document
|
|
28
|
+
*/
|
|
29
|
+
readonly documentId: DocumentId;
|
|
30
|
+
/**
|
|
31
|
+
* The underlying Automerge document handle
|
|
32
|
+
*/
|
|
33
|
+
readonly handle: DocHandle<T>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates an Automerge-repo store using standard Svelte stores
|
|
37
|
+
* @param repo A configured Automerge Repo instance
|
|
38
|
+
* @returns API for interacting with Automerge-repo
|
|
39
|
+
*/
|
|
40
|
+
export declare function createAutomergeStore(repo: Repo): {
|
|
41
|
+
find: <T>(automergeUrl: AutomergeUrl) => Promise<AutomergeDocumentStore<T> | null>;
|
|
42
|
+
create: <T>(initialContent?: any) => Promise<AutomergeDocumentStore<T>>;
|
|
43
|
+
delete: (automergeUrl: AutomergeUrl) => Promise<void>;
|
|
44
|
+
getRepo: () => Repo;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Create a document store from a document ID or URL
|
|
48
|
+
* Uses the repo from context if no repo is provided
|
|
49
|
+
* @param docIdOrUrl The document ID or URL
|
|
50
|
+
* @param repoInstance Optional Automerge Repo instance
|
|
51
|
+
* @returns A promise resolving to the document store
|
|
52
|
+
*/
|
|
53
|
+
export declare function document<T>(docIdOrUrl: DocumentId | AutomergeUrl, repoInstance?: Repo): Promise<AutomergeDocumentStore<T> | null>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { getContext, setContext } from "svelte";
|
|
2
|
+
import { writable } from "svelte/store";
|
|
3
|
+
// Store the repo in context for easy access
|
|
4
|
+
const REPO_CONTEXT_KEY = Symbol("automerge-repo");
|
|
5
|
+
/**
|
|
6
|
+
* Set the Automerge Repo in the Svelte context
|
|
7
|
+
* @param repo The Automerge Repo instance
|
|
8
|
+
*/
|
|
9
|
+
export function setContextRepo(repo) {
|
|
10
|
+
setContext(REPO_CONTEXT_KEY, repo);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the Automerge Repo from the Svelte context
|
|
14
|
+
* @returns The Automerge Repo instance
|
|
15
|
+
*/
|
|
16
|
+
export function getContextRepo() {
|
|
17
|
+
const repo = getContext(REPO_CONTEXT_KEY);
|
|
18
|
+
if (!repo) {
|
|
19
|
+
throw new Error("No Automerge Repo found in context. Did you call setContextRepo?");
|
|
20
|
+
}
|
|
21
|
+
return repo;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates an Automerge-repo store using standard Svelte stores
|
|
25
|
+
* @param repo A configured Automerge Repo instance
|
|
26
|
+
* @returns API for interacting with Automerge-repo
|
|
27
|
+
*/
|
|
28
|
+
export function createAutomergeStore(repo) {
|
|
29
|
+
if (!repo) {
|
|
30
|
+
throw new Error("A Repo instance is required");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Find a document by URL and create a reactive wrapper
|
|
34
|
+
*/
|
|
35
|
+
const find = async (automergeUrl) => {
|
|
36
|
+
const handle = await repo.find(automergeUrl);
|
|
37
|
+
if (!handle)
|
|
38
|
+
return null;
|
|
39
|
+
return createDocumentStore(handle);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Create a new document and wrap it with reactive state
|
|
43
|
+
*/
|
|
44
|
+
const create = async (initialContent = {}) => {
|
|
45
|
+
const handle = await repo.create(initialContent);
|
|
46
|
+
return createDocumentStore(handle);
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Delete a document
|
|
50
|
+
*/
|
|
51
|
+
const deleteDocument = async (automergeUrl) => {
|
|
52
|
+
repo.delete(automergeUrl);
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Create a reactive document store for a handle
|
|
56
|
+
*/
|
|
57
|
+
function createDocumentStore(handle) {
|
|
58
|
+
// Create a writable store with the current document
|
|
59
|
+
const { subscribe, set } = writable(handle.doc());
|
|
60
|
+
// Set up change listener
|
|
61
|
+
const onChange = ({ doc }) => {
|
|
62
|
+
set(doc);
|
|
63
|
+
};
|
|
64
|
+
// Subscribe to changes
|
|
65
|
+
handle.on("change", onChange);
|
|
66
|
+
// Create the store implementation
|
|
67
|
+
const store = {
|
|
68
|
+
subscribe,
|
|
69
|
+
set,
|
|
70
|
+
update: updater => {
|
|
71
|
+
const currentDoc = handle.doc();
|
|
72
|
+
const newValue = updater(currentDoc);
|
|
73
|
+
set(newValue);
|
|
74
|
+
},
|
|
75
|
+
// Method to make changes to the document
|
|
76
|
+
change(changeFn) {
|
|
77
|
+
return handle.change(changeFn);
|
|
78
|
+
},
|
|
79
|
+
// Metadata accessors
|
|
80
|
+
get url() {
|
|
81
|
+
return handle.url;
|
|
82
|
+
},
|
|
83
|
+
get documentId() {
|
|
84
|
+
return handle.documentId;
|
|
85
|
+
},
|
|
86
|
+
// Access to the underlying handle
|
|
87
|
+
get handle() {
|
|
88
|
+
return handle;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
return store;
|
|
92
|
+
}
|
|
93
|
+
// Return the store API
|
|
94
|
+
return {
|
|
95
|
+
find,
|
|
96
|
+
create,
|
|
97
|
+
delete: deleteDocument,
|
|
98
|
+
getRepo: () => repo,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create a document store from a document ID or URL
|
|
103
|
+
* Uses the repo from context if no repo is provided
|
|
104
|
+
* @param docIdOrUrl The document ID or URL
|
|
105
|
+
* @param repoInstance Optional Automerge Repo instance
|
|
106
|
+
* @returns A promise resolving to the document store
|
|
107
|
+
*/
|
|
108
|
+
export function document(docIdOrUrl, repoInstance) {
|
|
109
|
+
const repo = repoInstance || getContextRepo();
|
|
110
|
+
const store = createAutomergeStore(repo);
|
|
111
|
+
return store.find(docIdOrUrl);
|
|
112
|
+
}
|
package/package.json
CHANGED
|
@@ -1,21 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo-svelte-store",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.6",
|
|
4
4
|
"description": "A Svelte store containing your automerge documents",
|
|
5
5
|
"repository": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo-svelte-store",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"svelte": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
9
20
|
"scripts": {
|
|
10
|
-
"build": "",
|
|
11
|
-
"watch": "
|
|
21
|
+
"build": "svelte-package",
|
|
22
|
+
"watch": "svelte-package --watch"
|
|
12
23
|
},
|
|
13
24
|
"peerDependencies": {
|
|
14
|
-
"
|
|
15
|
-
"svelte": "^3.0.0 || ^4.0.0"
|
|
25
|
+
"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
|
16
26
|
},
|
|
17
27
|
"dependencies": {
|
|
18
|
-
"@automerge/automerge-repo": "2.0.0-beta.
|
|
28
|
+
"@automerge/automerge-repo": "2.0.0-beta.6"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@sveltejs/package": "^2.3.11",
|
|
32
|
+
"typescript": "^5.0.0"
|
|
19
33
|
},
|
|
20
34
|
"watch": {
|
|
21
35
|
"build": {
|
|
@@ -28,5 +42,5 @@
|
|
|
28
42
|
"publishConfig": {
|
|
29
43
|
"access": "public"
|
|
30
44
|
},
|
|
31
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "5f68e5e1bb41c5953d2024df2454becf755c38b8"
|
|
32
46
|
}
|
package/src/lib/index.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AutomergeUrl,
|
|
3
|
+
ChangeFn,
|
|
4
|
+
Doc,
|
|
5
|
+
DocHandle,
|
|
6
|
+
DocumentId,
|
|
7
|
+
Repo,
|
|
8
|
+
} from "@automerge/automerge-repo/slim"
|
|
9
|
+
|
|
10
|
+
import { getContext, setContext } from "svelte"
|
|
11
|
+
import { writable, type Writable } from "svelte/store"
|
|
12
|
+
|
|
13
|
+
// Store the repo in context for easy access
|
|
14
|
+
const REPO_CONTEXT_KEY = Symbol("automerge-repo")
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Set the Automerge Repo in the Svelte context
|
|
18
|
+
* @param repo The Automerge Repo instance
|
|
19
|
+
*/
|
|
20
|
+
export function setContextRepo(repo: Repo): void {
|
|
21
|
+
setContext(REPO_CONTEXT_KEY, repo)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get the Automerge Repo from the Svelte context
|
|
26
|
+
* @returns The Automerge Repo instance
|
|
27
|
+
*/
|
|
28
|
+
export function getContextRepo(): Repo {
|
|
29
|
+
const repo = getContext<Repo>(REPO_CONTEXT_KEY)
|
|
30
|
+
if (!repo) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
"No Automerge Repo found in context. Did you call setContextRepo?"
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
return repo
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The Automerge document store interface
|
|
40
|
+
*/
|
|
41
|
+
export interface AutomergeDocumentStore<T> extends Writable<Doc<T> | null> {
|
|
42
|
+
/**
|
|
43
|
+
* Make changes to the document
|
|
44
|
+
* @param changeFn Function that modifies the document
|
|
45
|
+
*/
|
|
46
|
+
change(changeFn: ChangeFn<T>): void
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The URL of the document
|
|
50
|
+
*/
|
|
51
|
+
readonly url: AutomergeUrl
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The ID of the document
|
|
55
|
+
*/
|
|
56
|
+
readonly documentId: DocumentId
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The underlying Automerge document handle
|
|
60
|
+
*/
|
|
61
|
+
readonly handle: DocHandle<T>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Creates an Automerge-repo store using standard Svelte stores
|
|
66
|
+
* @param repo A configured Automerge Repo instance
|
|
67
|
+
* @returns API for interacting with Automerge-repo
|
|
68
|
+
*/
|
|
69
|
+
export function createAutomergeStore(repo: Repo) {
|
|
70
|
+
if (!repo) {
|
|
71
|
+
throw new Error("A Repo instance is required")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Find a document by URL and create a reactive wrapper
|
|
76
|
+
*/
|
|
77
|
+
const find = async <T>(
|
|
78
|
+
automergeUrl: AutomergeUrl
|
|
79
|
+
): Promise<AutomergeDocumentStore<T> | null> => {
|
|
80
|
+
const handle = await repo.find<T>(automergeUrl)
|
|
81
|
+
if (!handle) return null
|
|
82
|
+
return createDocumentStore<T>(handle)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Create a new document and wrap it with reactive state
|
|
87
|
+
*/
|
|
88
|
+
const create = async <T>(
|
|
89
|
+
initialContent: any = {}
|
|
90
|
+
): Promise<AutomergeDocumentStore<T>> => {
|
|
91
|
+
const handle = await repo.create<T>(initialContent)
|
|
92
|
+
return createDocumentStore<T>(handle)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Delete a document
|
|
97
|
+
*/
|
|
98
|
+
const deleteDocument = async (automergeUrl: AutomergeUrl) => {
|
|
99
|
+
repo.delete(automergeUrl)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create a reactive document store for a handle
|
|
104
|
+
*/
|
|
105
|
+
function createDocumentStore<T>(
|
|
106
|
+
handle: DocHandle<T>
|
|
107
|
+
): AutomergeDocumentStore<T> {
|
|
108
|
+
// Create a writable store with the current document
|
|
109
|
+
const { subscribe, set } = writable<Doc<T> | null>(handle.doc())
|
|
110
|
+
|
|
111
|
+
// Set up change listener
|
|
112
|
+
const onChange = ({ doc }: { doc: Doc<T> }) => {
|
|
113
|
+
set(doc)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Subscribe to changes
|
|
117
|
+
handle.on("change", onChange)
|
|
118
|
+
|
|
119
|
+
// Create the store implementation
|
|
120
|
+
const store: AutomergeDocumentStore<T> = {
|
|
121
|
+
subscribe,
|
|
122
|
+
set,
|
|
123
|
+
update: updater => {
|
|
124
|
+
const currentDoc = handle.doc()
|
|
125
|
+
const newValue = updater(currentDoc)
|
|
126
|
+
set(newValue)
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Method to make changes to the document
|
|
130
|
+
change(changeFn: ChangeFn<T>) {
|
|
131
|
+
return handle.change(changeFn)
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// Metadata accessors
|
|
135
|
+
get url() {
|
|
136
|
+
return handle.url
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
get documentId() {
|
|
140
|
+
return handle.documentId
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Access to the underlying handle
|
|
144
|
+
get handle() {
|
|
145
|
+
return handle
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return store
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Return the store API
|
|
153
|
+
return {
|
|
154
|
+
find,
|
|
155
|
+
create,
|
|
156
|
+
delete: deleteDocument,
|
|
157
|
+
getRepo: () => repo,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a document store from a document ID or URL
|
|
163
|
+
* Uses the repo from context if no repo is provided
|
|
164
|
+
* @param docIdOrUrl The document ID or URL
|
|
165
|
+
* @param repoInstance Optional Automerge Repo instance
|
|
166
|
+
* @returns A promise resolving to the document store
|
|
167
|
+
*/
|
|
168
|
+
export function document<T>(
|
|
169
|
+
docIdOrUrl: DocumentId | AutomergeUrl,
|
|
170
|
+
repoInstance?: Repo
|
|
171
|
+
): Promise<AutomergeDocumentStore<T> | null> {
|
|
172
|
+
const repo = repoInstance || getContextRepo()
|
|
173
|
+
const store = createAutomergeStore(repo)
|
|
174
|
+
return store.find<T>(docIdOrUrl as AutomergeUrl)
|
|
175
|
+
}
|
package/src/index.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* # Svelte store for Automerge Repo
|
|
3
|
-
*
|
|
4
|
-
* ## Example Usage
|
|
5
|
-
*
|
|
6
|
-
* For a working example, see the [Svelte counter demo](../automerge-repo-demo-counter-svelte/).
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
*
|
|
10
|
-
* ```svelte
|
|
11
|
-
* // App.svelte
|
|
12
|
-
* <script lang="ts">
|
|
13
|
-
* import { Repo } from "@automerge/automerge-repo"
|
|
14
|
-
* import Counter from './lib/Counter.svelte'
|
|
15
|
-
* import { setContextRepo } from "@automerge/automerge-repo-svelte-store"
|
|
16
|
-
*
|
|
17
|
-
* const repo = new Repo({storage: new SomeStorage() })
|
|
18
|
-
*
|
|
19
|
-
* // Make the `Repo` available to child components (via Svelte's `setContext`).
|
|
20
|
-
* setContextRepo(repo)
|
|
21
|
-
*
|
|
22
|
-
* const docId = repo.create()
|
|
23
|
-
* </script>
|
|
24
|
-
*
|
|
25
|
-
* <main>
|
|
26
|
-
* <div class="card">
|
|
27
|
-
* <Counter {docId}/>
|
|
28
|
-
* </div>
|
|
29
|
-
* </main>
|
|
30
|
-
* ```
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* ```svelte
|
|
34
|
-
* // Counter.svelte`
|
|
35
|
-
* <script lang="ts">
|
|
36
|
-
* import type { DocumentId } from "@automerge/automerge-repo"
|
|
37
|
-
* import { document } from "@automerge/automerge-repo-svelte-store"
|
|
38
|
-
*
|
|
39
|
-
* export let docId: DocumentId
|
|
40
|
-
*
|
|
41
|
-
* // `document` calls `getContextRepo` internally to access the closest `Repo`.
|
|
42
|
-
* // alternatively, you may pass in a specific repo as the second parameter
|
|
43
|
-
* const doc = document<{count?: number}>(docId)
|
|
44
|
-
* const increment = () => {
|
|
45
|
-
* doc.change((d) => d.count = (d.count || 0) + 1)
|
|
46
|
-
* }
|
|
47
|
-
* </script>
|
|
48
|
-
*
|
|
49
|
-
* <button on:click={increment}>
|
|
50
|
-
* count is {$doc?.count || 0}
|
|
51
|
-
* </button>
|
|
52
|
-
* ```
|
|
53
|
-
*
|
|
54
|
-
* ## Contributors
|
|
55
|
-
* Originally written by Dylan MacKenzie ([@ecstatic-morse](https://github.com/ecstatic-morse)).
|
|
56
|
-
* * @packageDocumentation
|
|
57
|
-
**/
|
|
58
|
-
|
|
59
|
-
import type { ChangeFn, Doc } from "@automerge/automerge/slim/next"
|
|
60
|
-
import {
|
|
61
|
-
AutomergeUrl,
|
|
62
|
-
DocHandleChangePayload,
|
|
63
|
-
Repo,
|
|
64
|
-
} from "@automerge/automerge-repo/slim"
|
|
65
|
-
import { getContext, setContext } from "svelte"
|
|
66
|
-
import { writable } from "svelte/store"
|
|
67
|
-
|
|
68
|
-
const ContextRepoKey = Symbol("svelte-context-automerge-repo")
|
|
69
|
-
|
|
70
|
-
export function getContextRepo(): Repo {
|
|
71
|
-
return getContext<Repo>(ContextRepoKey)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function setContextRepo(repo: Repo) {
|
|
75
|
-
setContext(ContextRepoKey, repo)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* A Svelte store for an Automerge document.
|
|
80
|
-
*
|
|
81
|
-
* @param {AutomergeUrl} documentId - The Automerge document ID
|
|
82
|
-
* @param {Repo=} repo - (Optional) The Automerge repo to use. If not provided, the repo will be retrieved from context.
|
|
83
|
-
*
|
|
84
|
-
* @returns A Svelte store for the Automerge document.
|
|
85
|
-
*/
|
|
86
|
-
|
|
87
|
-
export function document<T>(documentId: AutomergeUrl, repo?: Repo) {
|
|
88
|
-
repo = repo ?? getContextRepo()
|
|
89
|
-
const handle = repo.find<T>(documentId)
|
|
90
|
-
const { set, subscribe } = writable<Doc<T>>(handle.doc(), () => {
|
|
91
|
-
const onChange = (h: DocHandleChangePayload<T>) => set(h.doc)
|
|
92
|
-
handle.addListener("change", onChange)
|
|
93
|
-
return () => handle.removeListener("change", onChange)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
subscribe,
|
|
98
|
-
change: (fn: ChangeFn<T>) => {
|
|
99
|
-
handle.change(fn)
|
|
100
|
-
},
|
|
101
|
-
}
|
|
102
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"jsx": "react",
|
|
5
|
-
"module": "NodeNext",
|
|
6
|
-
"moduleResolution": "Node16",
|
|
7
|
-
"declaration": true,
|
|
8
|
-
"declarationMap": true,
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"strict": true,
|
|
13
|
-
"skipLibCheck": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*.ts"]
|
|
16
|
-
}
|