@automerge/automerge-repo-solid-primitives 2.2.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/.assets/automerge.png +0 -0
- package/.assets/solid.png +0 -0
- package/.github/workflows/tests.yml +28 -0
- package/.github/workflows/typedoc.yml +53 -0
- package/LICENSE +21 -0
- package/dist/autoproduce.d.ts +13 -0
- package/dist/context.d.ts +9 -0
- package/dist/createDocumentProjection.d.ts +10 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +912 -0
- package/dist/makeDocumentProjection.d.ts +8 -0
- package/dist/types.d.ts +7 -0
- package/dist/useDocHandle.d.ts +15 -0
- package/dist/useDocument.d.ts +9 -0
- package/dist/useRepo.d.ts +4 -0
- package/package.json +47 -0
- package/readme.md +139 -0
- package/src/autoproduce.ts +18 -0
- package/src/context.ts +11 -0
- package/src/createDocumentProjection.ts +19 -0
- package/src/index.ts +7 -0
- package/src/makeDocumentProjection.ts +73 -0
- package/src/types.ts +9 -0
- package/src/useDocHandle.ts +90 -0
- package/src/useDocument.ts +21 -0
- package/src/useRepo.ts +10 -0
- package/test/createDocumentProjection.test.tsx +394 -0
- package/test/makeDocumentProjection.test.tsx +290 -0
- package/test/useDocHandle.test.tsx +183 -0
- package/test/useDocument.test.tsx +337 -0
- package/test/useRepo.test.tsx +34 -0
- package/tsconfig.build.json +21 -0
- package/tsconfig.json +11 -0
- package/tsconfig.test.json +20 -0
- package/typedoc.json +5 -0
- package/vite.config.ts +41 -0
- package/vitest.config.ts +25 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Doc, DocHandle } from '@automerge/automerge-repo/slim';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* make a fine-grained live view of a document from its handle.
|
|
5
|
+
* @param handle an Automerge
|
|
6
|
+
* [DocHandle](https://automerge.org/automerge-repo/classes/_automerge_automerge_repo.DocHandle.html)
|
|
7
|
+
*/
|
|
8
|
+
export default function makeDocumentProjection<T extends object>(handle: DocHandle<T>): Doc<T>;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AutomergeUrl, DocHandle } from '@automerge/automerge-repo/slim';
|
|
2
|
+
import { Resource } from 'solid-js';
|
|
3
|
+
import { MaybeAccessor, UseDocHandleOptions } from './types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* get a
|
|
7
|
+
* [DocHandle](https://automerge.org/automerge-repo/classes/_automerge_automerge_repo.DocHandle.html)
|
|
8
|
+
* from an
|
|
9
|
+
* [AutomergeUrl](https://automerge.org/automerge-repo/types/_automerge_automerge_repo.AutomergeUrl.html)
|
|
10
|
+
* as a
|
|
11
|
+
* [Resource](https://docs.solidjs.com/reference/basic-reactivity/create-resource).
|
|
12
|
+
* Waits for the handle to be
|
|
13
|
+
* [ready](https://automerge.org/automerge-repo/variables/_automerge_automerge_repo.HandleState-1.html).
|
|
14
|
+
*/
|
|
15
|
+
export default function useDocHandle<T>(url: MaybeAccessor<AutomergeUrl | undefined>, options?: UseDocHandleOptions): Resource<DocHandle<T> | undefined>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AutomergeUrl, Doc, DocHandle } from '@automerge/automerge-repo/slim';
|
|
2
|
+
import { MaybeAccessor, UseDocHandleOptions } from './types.js';
|
|
3
|
+
import { Accessor, Resource } from 'solid-js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* get a fine-grained live view of a document, and its handle, from a URL.
|
|
7
|
+
* @param url a function that returns a url
|
|
8
|
+
*/
|
|
9
|
+
export default function useDocument<T extends object>(url: MaybeAccessor<AutomergeUrl | undefined>, options?: UseDocHandleOptions): [Accessor<Doc<T> | undefined>, Resource<DocHandle<T> | undefined>];
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@automerge/automerge-repo-solid-primitives",
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Access Automerge Repo in your SolidJS application",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc --noEmit && vite build",
|
|
9
|
+
"test": "vitest run",
|
|
10
|
+
"watch": "npm-watch build",
|
|
11
|
+
"visualize": "VISUALIZE=true vite build"
|
|
12
|
+
},
|
|
13
|
+
"author": "chee <chee@rabbits.computer>",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@automerge/automerge": "3.0.0",
|
|
17
|
+
"@automerge/automerge-repo": "2.2.0",
|
|
18
|
+
"@solidjs/testing-library": "^0.8.9",
|
|
19
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
20
|
+
"@testing-library/user-event": "^14.5.2",
|
|
21
|
+
"rollup-plugin-visualizer": "^5.9.3",
|
|
22
|
+
"solid-js": "^1.9.4",
|
|
23
|
+
"vite-plugin-dts": "^3.9.1",
|
|
24
|
+
"vite-plugin-solid": "^2.11.0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@automerge/automerge": "3.0.0",
|
|
28
|
+
"solid-js": "^1.9.4"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/automerge/automerge-repo.git"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo-solid-primitives",
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"watch": {
|
|
39
|
+
"build": {
|
|
40
|
+
"patterns": "./src/**/*",
|
|
41
|
+
"extensions": [
|
|
42
|
+
".ts"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"gitHead": "0eab1c635365712017d7ccc000e7cd92f14e7143"
|
|
47
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Solid Automerge
|
|
2
|
+
|
|
3
|
+
<a href="https://www.solidjs.com/"> <img alt="" src=.assets/solid.png width=22
|
|
4
|
+
height=22> Solid </a> primitives for <a
|
|
5
|
+
href="https://automerge.org/docs/repositories/"> <img alt=""
|
|
6
|
+
src=.assets/automerge.png width=22 height=22>Automerge</a> .
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm add solidjs @automerge/automerge-repo
|
|
10
|
+
pnpm add solid-automerge
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
or, say:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
deno add --npm solidjs @automerge/vanillajs
|
|
17
|
+
deno add jsr:@chee/solid-automerge
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## useDocument ✨
|
|
21
|
+
|
|
22
|
+
Get a fine-grained live view of an automerge document from its URL.
|
|
23
|
+
|
|
24
|
+
When the handle receives changes, it converts the incoming automerge patch ops
|
|
25
|
+
to precise solid store updates, giving you fine-grained reactivity that's
|
|
26
|
+
consistent across space and time.
|
|
27
|
+
|
|
28
|
+
Returns `[doc, handle]`.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
useDocument<T>(
|
|
32
|
+
() => AutomergeURL,
|
|
33
|
+
options?: {repo: Repo}
|
|
34
|
+
): [Doc<T>, DocHandle<T>]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
// example
|
|
39
|
+
const [url, setURL] = createSignal<AutomergeUrl>(props.url)
|
|
40
|
+
const [doc, handle] = useDocument(url, { repo })
|
|
41
|
+
|
|
42
|
+
const inc = () => handle()?.change(d => d.count++)
|
|
43
|
+
return <button onclick={inc}>{doc()?.count}</button>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The `{repo}` option can be left out if you are using [RepoContext](#repocontext).
|
|
47
|
+
|
|
48
|
+
## createDocumentProjection
|
|
49
|
+
|
|
50
|
+
Get a fine-grained live view from a signal automerge `DocHandle`.
|
|
51
|
+
|
|
52
|
+
Underlying primitive for [`useDocument`](#usedocument-).
|
|
53
|
+
|
|
54
|
+
Works with [`useHandle`](#usehandle).
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
createDocumentProjection<T>(() => AutomergeUrl): Doc<T>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
// example
|
|
62
|
+
const handle = repo.find(url)
|
|
63
|
+
const doc = makeDocumentProjection<{ items: { title: string }[] }>(handle)
|
|
64
|
+
|
|
65
|
+
// subscribes fine-grained to doc.items[1].title
|
|
66
|
+
return <h1>{doc.items[1].title}</h1>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## makeDocumentProjection
|
|
70
|
+
|
|
71
|
+
Just like `createDocumentProjection`, but without a reactive input.
|
|
72
|
+
|
|
73
|
+
Underlying primitive for [`createDocumentProjection`](#createDocumentProjection).
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
makeDocumentProjection<T>(handle: Handle<T>): Doc<T>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
// example
|
|
81
|
+
const handle = repo.find(url)
|
|
82
|
+
const doc = makeDocumentProjection<{ items: { title: string }[] }>(handle)
|
|
83
|
+
|
|
84
|
+
// subscribes fine-grained to doc.items[1].title
|
|
85
|
+
return <h1>{doc.items[1].title}</h1>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## useDocHandle
|
|
89
|
+
|
|
90
|
+
Get a [DocHandle](https://automerge.org/docs/repositories/dochandles/) from the
|
|
91
|
+
repo as a
|
|
92
|
+
[resource](https://docs.solidjs.com/reference/basic-reactivity/create-resource).
|
|
93
|
+
|
|
94
|
+
Perfect for handing to `createDocumentProjection`.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
useDocHandle<T>(
|
|
98
|
+
() => AnyDocumentId,
|
|
99
|
+
options?: {repo: Repo}
|
|
100
|
+
): Resource<Handle<T>>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
const handle = useDocHandle(id, { repo })
|
|
105
|
+
// or
|
|
106
|
+
const handle = useDocHandle(id)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The `repo` option can be left out if you are using [RepoContext](#repocontext).
|
|
110
|
+
|
|
111
|
+
## context
|
|
112
|
+
|
|
113
|
+
If you prefer the context pattern for some reason, you can pass the repo higher
|
|
114
|
+
up in your app with `RepoContext`
|
|
115
|
+
|
|
116
|
+
### `RepoContext`
|
|
117
|
+
|
|
118
|
+
A convenience context for Automerge-Repo Solid apps. Optional: if you prefer you
|
|
119
|
+
can pass a repo as an option to `useDocHandle` and `useDocument`.
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<RepoContext.Provider repo={Repo}>
|
|
123
|
+
<App />
|
|
124
|
+
</RepoContext.Provider>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `useRepo`
|
|
128
|
+
|
|
129
|
+
Get the repo from the [context](#repocontext).
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
useRepo(): Repo
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### e.g.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const repo = useRepo()
|
|
139
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DocHandleChangePayload } from "@automerge/automerge-repo/slim"
|
|
2
|
+
import { applyPatches } from "@automerge/automerge/slim"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* convert automerge patches to solid producer operations
|
|
6
|
+
* @param payload the
|
|
7
|
+
* [DocHandleChangePayload](https://automerge.org/automerge-repo/interfaces/_automerge_automerge_repo.DocHandleChangePayload.html)
|
|
8
|
+
* from the handle.on("change
|
|
9
|
+
* @returns a callback for an immer-like function. e.g.
|
|
10
|
+
* [produce](https://docs.solidjs.com/reference/store-utilities/produce) for
|
|
11
|
+
* [Solid
|
|
12
|
+
* Stores](https://docs.solidjs.com/reference/store-utilities/create-store)
|
|
13
|
+
*/
|
|
14
|
+
export default function autoproduce<T>(
|
|
15
|
+
payload: DocHandleChangePayload<T>
|
|
16
|
+
): (doc: T) => void {
|
|
17
|
+
return (doc: T) => applyPatches(doc, payload.patches)
|
|
18
|
+
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Repo } from "@automerge/automerge-repo/slim"
|
|
2
|
+
import { createContext, type Context } from "solid-js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* a [context](https://docs.solidjs.com/concepts/context) that provides access
|
|
6
|
+
* to an Automerge Repo. you don't need this, you can pass the repo in the
|
|
7
|
+
* second arg to the functions that need it.
|
|
8
|
+
*/
|
|
9
|
+
export const RepoContext: Context<Repo | null> = createContext<Repo | null>(
|
|
10
|
+
null
|
|
11
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createMemo, type Accessor } from "solid-js"
|
|
2
|
+
import { type DocHandle, type Doc } from "@automerge/automerge-repo/slim"
|
|
3
|
+
import makeDocumentProjection from "./makeDocumentProjection.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* get a fine-grained live view of a document from a handle. works with
|
|
7
|
+
* {@link useDocHandle}.
|
|
8
|
+
* @param handle an accessor (signal/resource) of a
|
|
9
|
+
* [DocHandle](https://automerge.org/automerge-repo/classes/_automerge_automerge_repo.DocHandle.html)
|
|
10
|
+
*/
|
|
11
|
+
export default function createDocumentProjection<T extends object>(
|
|
12
|
+
handle: Accessor<DocHandle<T> | undefined>
|
|
13
|
+
): Accessor<Doc<T> | undefined> {
|
|
14
|
+
const projection = createMemo<Doc<T> | undefined>(() => {
|
|
15
|
+
const unwrappedHandle = typeof handle == "function" ? handle() : handle
|
|
16
|
+
return unwrappedHandle && makeDocumentProjection<T>(unwrappedHandle)
|
|
17
|
+
})
|
|
18
|
+
return projection
|
|
19
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as autoproduce } from "./autoproduce.js"
|
|
2
|
+
export { default as useDocument } from "./useDocument.js"
|
|
3
|
+
export { default as useDocHandle } from "./useDocHandle.js"
|
|
4
|
+
export { default as makeDocumentProjection } from "./makeDocumentProjection.js"
|
|
5
|
+
export { default as createDocumentProjection } from "./createDocumentProjection.js"
|
|
6
|
+
export { default as useRepo } from "./useRepo.js"
|
|
7
|
+
export { RepoContext } from "./context.js"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { onCleanup } from "solid-js"
|
|
2
|
+
import type {
|
|
3
|
+
Doc,
|
|
4
|
+
DocHandle,
|
|
5
|
+
DocHandleChangePayload,
|
|
6
|
+
} from "@automerge/automerge-repo/slim"
|
|
7
|
+
import autoproduce from "./autoproduce.js"
|
|
8
|
+
import { createStore, produce, reconcile, type Store } from "solid-js/store"
|
|
9
|
+
import { applyPatches, diff, getHeads } from "@automerge/automerge/slim"
|
|
10
|
+
|
|
11
|
+
const cache = new WeakMap<
|
|
12
|
+
DocHandle<unknown>,
|
|
13
|
+
{
|
|
14
|
+
refs: number
|
|
15
|
+
store: Store<Doc<unknown>>
|
|
16
|
+
cleanup(): void
|
|
17
|
+
}
|
|
18
|
+
>()
|
|
19
|
+
|
|
20
|
+
function initial<T>(handle: DocHandle<T>): T {
|
|
21
|
+
const template = {} as T
|
|
22
|
+
applyPatches(template, diff(handle.doc(), [], getHeads(handle.doc())))
|
|
23
|
+
return template
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* make a fine-grained live view of a document from its handle.
|
|
28
|
+
* @param handle an Automerge
|
|
29
|
+
* [DocHandle](https://automerge.org/automerge-repo/classes/_automerge_automerge_repo.DocHandle.html)
|
|
30
|
+
*/
|
|
31
|
+
export default function makeDocumentProjection<T extends object>(
|
|
32
|
+
handle: DocHandle<T>
|
|
33
|
+
): Doc<T> {
|
|
34
|
+
onCleanup(() => {
|
|
35
|
+
const item = cache.get(handle)!
|
|
36
|
+
if (!item) return
|
|
37
|
+
if (!item.refs--) {
|
|
38
|
+
item.cleanup()
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
if (cache.has(handle)) {
|
|
43
|
+
const item = cache.get(handle)!
|
|
44
|
+
item.refs++
|
|
45
|
+
return item.store as T
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const [doc, set] = createStore<T>(initial(handle))
|
|
49
|
+
|
|
50
|
+
cache.set(handle, {
|
|
51
|
+
refs: 0,
|
|
52
|
+
store: doc,
|
|
53
|
+
cleanup() {
|
|
54
|
+
handle.off("change", patch)
|
|
55
|
+
handle.off("delete", ondelete)
|
|
56
|
+
// https://github.com/chee/solid-automerge/pull/5
|
|
57
|
+
cache.delete(handle)
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
function patch(payload: DocHandleChangePayload<T>) {
|
|
62
|
+
set(produce(autoproduce(payload)))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ondelete() {
|
|
66
|
+
set(reconcile({} as T))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
handle.on("change", patch)
|
|
70
|
+
handle.on("delete", ondelete)
|
|
71
|
+
|
|
72
|
+
return doc
|
|
73
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AutomergeUrl,
|
|
3
|
+
DocHandle,
|
|
4
|
+
DocumentId,
|
|
5
|
+
HandleState,
|
|
6
|
+
} from "@automerge/automerge-repo/slim"
|
|
7
|
+
import {
|
|
8
|
+
createEffect,
|
|
9
|
+
createResource,
|
|
10
|
+
useContext,
|
|
11
|
+
type Resource,
|
|
12
|
+
} from "solid-js"
|
|
13
|
+
import { RepoContext } from "./context.js"
|
|
14
|
+
import type { MaybeAccessor, UseDocHandleOptions } from "./types.js"
|
|
15
|
+
const readyStates = ["ready", "deleted", "unavailable"] as HandleState[]
|
|
16
|
+
const badStates = ["deleted", "unavailable"] as HandleState[]
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* get a
|
|
20
|
+
* [DocHandle](https://automerge.org/automerge-repo/classes/_automerge_automerge_repo.DocHandle.html)
|
|
21
|
+
* from an
|
|
22
|
+
* [AutomergeUrl](https://automerge.org/automerge-repo/types/_automerge_automerge_repo.AutomergeUrl.html)
|
|
23
|
+
* as a
|
|
24
|
+
* [Resource](https://docs.solidjs.com/reference/basic-reactivity/create-resource).
|
|
25
|
+
* Waits for the handle to be
|
|
26
|
+
* [ready](https://automerge.org/automerge-repo/variables/_automerge_automerge_repo.HandleState-1.html).
|
|
27
|
+
*/
|
|
28
|
+
export default function useDocHandle<T>(
|
|
29
|
+
url: MaybeAccessor<AutomergeUrl | undefined>,
|
|
30
|
+
options?: UseDocHandleOptions
|
|
31
|
+
): Resource<DocHandle<T> | undefined> {
|
|
32
|
+
const contextRepo = useContext(RepoContext)
|
|
33
|
+
|
|
34
|
+
if (!options?.repo && !contextRepo) {
|
|
35
|
+
throw new Error("use outside <RepoContext> requires options.repo")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const repo = (options?.repo || contextRepo)!
|
|
39
|
+
|
|
40
|
+
function getExistingHandle() {
|
|
41
|
+
if (options?.["~skipInitialValue"]) return undefined
|
|
42
|
+
const unwrappedURL = typeof url == "function" ? url() : url
|
|
43
|
+
if (!unwrappedURL) return undefined
|
|
44
|
+
try {
|
|
45
|
+
const documentId = new URL(unwrappedURL).pathname as DocumentId
|
|
46
|
+
const existingHandle = repo.handles[documentId]
|
|
47
|
+
if (existingHandle?.isReady()) {
|
|
48
|
+
return existingHandle as DocHandle<T>
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error("Error parsing URL:", error)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const [handle, { mutate }] = createResource(
|
|
56
|
+
url,
|
|
57
|
+
async url => {
|
|
58
|
+
const handle = await repo.find<T>(url, {
|
|
59
|
+
allowableStates: readyStates,
|
|
60
|
+
})
|
|
61
|
+
const reject = (state: HandleState) =>
|
|
62
|
+
Promise.reject(new Error(`document not available: [${state}]`))
|
|
63
|
+
|
|
64
|
+
if (handle.isReady()) {
|
|
65
|
+
return handle
|
|
66
|
+
} else if (handle.inState(badStates)) {
|
|
67
|
+
return reject(handle.state)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return handle.whenReady(readyStates).then(() => {
|
|
71
|
+
if (handle.isReady()) {
|
|
72
|
+
return handle
|
|
73
|
+
}
|
|
74
|
+
return reject(handle.state)
|
|
75
|
+
})
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
initialValue: getExistingHandle(),
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
createEffect(() => {
|
|
83
|
+
const unwrappedURL = typeof url == "function" ? url() : url
|
|
84
|
+
if (!unwrappedURL) {
|
|
85
|
+
mutate()
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return handle
|
|
90
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AutomergeUrl,
|
|
3
|
+
Doc,
|
|
4
|
+
DocHandle,
|
|
5
|
+
} from "@automerge/automerge-repo/slim"
|
|
6
|
+
import createDocumentProjection from "./createDocumentProjection.js"
|
|
7
|
+
import useDocHandle from "./useDocHandle.js"
|
|
8
|
+
import type { MaybeAccessor, UseDocHandleOptions } from "./types.js"
|
|
9
|
+
import type { Accessor, Resource } from "solid-js"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* get a fine-grained live view of a document, and its handle, from a URL.
|
|
13
|
+
* @param url a function that returns a url
|
|
14
|
+
*/
|
|
15
|
+
export default function useDocument<T extends object>(
|
|
16
|
+
url: MaybeAccessor<AutomergeUrl | undefined>,
|
|
17
|
+
options?: UseDocHandleOptions
|
|
18
|
+
): [Accessor<Doc<T> | undefined>, Resource<DocHandle<T> | undefined>] {
|
|
19
|
+
const handle = useDocHandle<T>(url, options)
|
|
20
|
+
return [createDocumentProjection<T>(handle), handle] as const
|
|
21
|
+
}
|
package/src/useRepo.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Repo } from "@automerge/automerge-repo/slim"
|
|
2
|
+
import { RepoContext } from "./context.js"
|
|
3
|
+
import { useContext } from "solid-js"
|
|
4
|
+
|
|
5
|
+
/** grab the repo from the {@link RepoContext} */
|
|
6
|
+
export default function useRepo(): Repo {
|
|
7
|
+
const repo = useContext(RepoContext)
|
|
8
|
+
if (!repo) throw new Error("Please wrap me in a <RepoContext value={repo}>")
|
|
9
|
+
return repo
|
|
10
|
+
}
|