@tinycloud/replica 0.1.0-beta.1 → 0.1.0-beta.2
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 +100 -0
- package/dist/replica.worker.js +541 -169
- package/dist/replica.worker.js.map +1 -1
- package/package.json +2 -2
- package/dist/browser.d.ts +0 -334
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# @tinycloud/replica
|
|
2
|
+
|
|
3
|
+
A durable, read-only local replica of one TinyCloud KV prefix. Sync while online; read the latest locally observed values while offline. Replicas do not support offline writes or SQL data.
|
|
4
|
+
|
|
5
|
+
**Status: beta / release candidate (Replication RC1).** APIs, limitations, and release versions may change.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- The TinyCloud node must advertise `kv-sync-v1` in its `/info` response.
|
|
10
|
+
- Node.js 22.13 or later, or Bun, for SQLite storage.
|
|
11
|
+
- Browser: IndexedDB for durable storage and Web Locks for `sync()`; without Web Locks, local reads remain available but sync is unsupported.
|
|
12
|
+
- A device grant covering the configured prefix with both `get` and `sync` abilities.
|
|
13
|
+
|
|
14
|
+
Install an explicit version; do not rely on a moving dist-tag:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install @tinycloud/replica@0.1.0-beta.1
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Browser
|
|
21
|
+
|
|
22
|
+
Import the browser API from `@tinycloud/replica/browser`. Open a replica with the signed-in user's identity DID as `principal`, install a device UCAN grant, sync, then read locally:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { openReplica, ReplicaError } from "@tinycloud/replica/browser";
|
|
26
|
+
|
|
27
|
+
declare const spaceId: string;
|
|
28
|
+
declare const signedInUserDid: string;
|
|
29
|
+
declare const deviceGrant: string;
|
|
30
|
+
|
|
31
|
+
const replica = await openReplica({
|
|
32
|
+
host: "https://tee.node.tinycloud.xyz",
|
|
33
|
+
space: spaceId,
|
|
34
|
+
prefix: "notes/",
|
|
35
|
+
principal: signedInUserDid,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Supply the compact UCAN issued to this replica's device DID.
|
|
40
|
+
await replica.installGrant(deviceGrant);
|
|
41
|
+
const report = await replica.sync();
|
|
42
|
+
if (report.status === "busy") {
|
|
43
|
+
console.log("Another tab is syncing.");
|
|
44
|
+
} else {
|
|
45
|
+
// get() and list() only read local storage; neither falls back to the network.
|
|
46
|
+
const result = await replica.get("notes/today.txt");
|
|
47
|
+
if (result.status === "present") {
|
|
48
|
+
const text = new TextDecoder().decode(result.value);
|
|
49
|
+
console.log(text);
|
|
50
|
+
}
|
|
51
|
+
const keys = await replica.list({ prefix: "notes/" });
|
|
52
|
+
console.log(keys.entries.map(({ key }) => key));
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof ReplicaError) {
|
|
56
|
+
switch (error.code) {
|
|
57
|
+
case "GRANT_MISSING":
|
|
58
|
+
case "GRANT_EXPIRED":
|
|
59
|
+
case "GRANT_REVOKED":
|
|
60
|
+
// Install or renew authority before syncing/reading.
|
|
61
|
+
break;
|
|
62
|
+
case "SECRETS_OPT_IN_REQUIRED":
|
|
63
|
+
case "NOT_COVERED":
|
|
64
|
+
case "RUNTIME_UNSUPPORTED":
|
|
65
|
+
case "NETWORK_ERROR":
|
|
66
|
+
console.error(error.code, error.message);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
} finally {
|
|
72
|
+
await replica.close();
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`openReplica()` requires `host`, native-form `space`, `prefix`, and `principal`. The principal partitions replicas for signed-in users sharing an origin; it is not an authorization check. The node authorizes each sync. `deviceGrant` above is the compact delegation string (for example `issued.delegation.delegationHeader.Authorization`) for `replica.deviceDid`; the owner must authorize `get` and `sync` on the prefix.
|
|
77
|
+
|
|
78
|
+
`get()` may return `present`, `content_missing`, `deleted`, `absent`, `coverage_incomplete`, or `not_covered`. Check its status before using a value. `sync()` returns `synced` with a report or `busy` when another tab holds the sync lock. Errors are `ReplicaError` instances with a stable `code`; browser exports `ReplicaError` and `ReplicaErrorCode` from its entry point. Local reads never make network requests, but they remain subject to grant and retention authority.
|
|
79
|
+
|
|
80
|
+
## Node and SQLite
|
|
81
|
+
|
|
82
|
+
The SQLite store API is exported directly from `@tinycloud/replica/sqlite`:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { SqliteReplicaStore, loadSqlite } from "@tinycloud/replica/sqlite";
|
|
86
|
+
|
|
87
|
+
const store = await SqliteReplicaStore.open("./replica-data", { create: true });
|
|
88
|
+
// Pass `store` to `new Replica({ store, transport })` from `@tinycloud/replica`.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`SqliteReplicaStore.open()` defaults to the runtime's built-in SQLite driver: `node:sqlite` on Node 22.13+ or `bun:sqlite` on Bun. For a managed CLI workflow, use `tc replica` from `@tinycloud/cli`.
|
|
92
|
+
|
|
93
|
+
## Security and storage
|
|
94
|
+
|
|
95
|
+
- A replica stores only the configured KV prefix. The grant may be broader, but keys and values outside the replica prefix are not stored.
|
|
96
|
+
- Reads stop when the sync grant expires. A separate node-attested retention grant can allow already-synced reads for a bounded period after expiry; it does not authorize more syncs. A learned revocation blocks reads.
|
|
97
|
+
- Replicating the secrets space or a prefix overlapping the `vault` namespace (including bare `vault`) requires explicit `allowSecrets: true` opt-in. This copies encrypted secret material; it does not grant decryption. Decrypt authority is network-wide, not limited to a secret name (TC-755).
|
|
98
|
+
- SQLite replica files are mode `0600`; replica data directories are mode `0700`. Browser storage is scoped to the origin; same-origin scripts can access that origin's IndexedDB.
|
|
99
|
+
|
|
100
|
+
See the [full local replicas guide](https://docs.tinycloud.xyz/guides/local-replicas) for grant setup, CLI usage, retention, error handling, and limitations.
|