@x-otto/persistence 0.0.1-alpha.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 +134 -0
- package/dist/index.d.ts +984 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @x-otto/persistence
|
|
2
|
+
|
|
3
|
+
Unified snapshot persistence + append-only log abstraction. Backends: memory, file (atomic write), HTTP REST, SQLite.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @x-otto/persistence
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createPersistence, createAppendLog } from '@x-otto/persistence'
|
|
15
|
+
|
|
16
|
+
// File-backed snapshot persistence (atomic .tmp → rename)
|
|
17
|
+
const store = createPersistence({ type: 'file', path: '/tmp/data' })
|
|
18
|
+
await store.save('my-key', { hello: 'world' })
|
|
19
|
+
const snap = await store.load('my-key')
|
|
20
|
+
// snap → Snapshot<{ hello: string }>
|
|
21
|
+
|
|
22
|
+
// Append-only log (memory)
|
|
23
|
+
const log = createAppendLog({ type: 'memory' })
|
|
24
|
+
const seq = log.append('stream-1', { event: 'start' })
|
|
25
|
+
log.append('stream-1', { event: 'end' })
|
|
26
|
+
const entries = log.read('stream-1', 0, 10)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Backends
|
|
30
|
+
|
|
31
|
+
| Backend | Kind | Save | Load | List | Delete | Notes |
|
|
32
|
+
|-----------------|-------------|-----------------|----------|------|--------|----------------------------------|
|
|
33
|
+
| Memory | `memory` | `structuredClone` | `structuredClone` | ✓ | ✓ | Test / ephemeral |
|
|
34
|
+
| File | `file` | `.tmp` → `rename` | ✓ | ✓ | ✓ | Atomic per-file, mtime sort |
|
|
35
|
+
| HTTP | `http` | `PUT /:id` | `GET /:id` | ✓ | ✓ | Bearer token + ETag, fetch injected |
|
|
36
|
+
| SQLite | `sqlite` | `INSERT OR REPLACE` | ✓ | ✓ | ✓ | WAL mode, change_log per mutation |
|
|
37
|
+
|
|
38
|
+
All backends support `listPaginated(page, pageSize)` returning `PaginatedResult<T>`.
|
|
39
|
+
|
|
40
|
+
## AppendLog
|
|
41
|
+
|
|
42
|
+
Orthogonal append-only primitive alongside snapshots:
|
|
43
|
+
|
|
44
|
+
| Backend | Kind | Write | Read | Notes |
|
|
45
|
+
|---------|---------|--------------------------------|--------------------------|--------------------------|
|
|
46
|
+
| Memory | `memory` | Array push + listener broadcast | Full / range (0-based seq) | Real-time tail via events |
|
|
47
|
+
| File | `file` | `.jsonl` per stream, write queue | Range read, crash-tail repair | Line-level truncate |
|
|
48
|
+
| SQLite | `sqlite` | `append_entries` table, WAL | Range read + `COUNT(*)` | Shared connection via `sqlite-db-cache` |
|
|
49
|
+
|
|
50
|
+
## Snapshot<T> Envelope
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
interface Snapshot<T> {
|
|
54
|
+
id: string
|
|
55
|
+
version: number
|
|
56
|
+
data: T
|
|
57
|
+
metadata: {
|
|
58
|
+
createdAt: number
|
|
59
|
+
updatedAt: number
|
|
60
|
+
tags?: string[]
|
|
61
|
+
[key: string]: unknown
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Use `saveDocument(persistence, id, data, opts)` as the single source of truth for envelope construction — consumers don't hand-roll `{version, id, data, metadata}`.
|
|
67
|
+
|
|
68
|
+
## StorageHost
|
|
69
|
+
|
|
70
|
+
Server-side semantic layer for the `RemotePersistence` wire protocol (consumed by `@x-otto/service`):
|
|
71
|
+
|
|
72
|
+
- Namespace whitelist + lazy per-namespace Persistence instance
|
|
73
|
+
- Snapshot envelope wrapping/unwrapping
|
|
74
|
+
- `getChangesSince` — incremental sync data source
|
|
75
|
+
- `streamEvents` — SSE change events (SQLite-backed only, duck-type detection)
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { createFileStorageHost } from '@x-otto/persistence'
|
|
79
|
+
|
|
80
|
+
const host = createFileStorageHost({ baseDir: './data', namespaces: ['sessions', 'knowledge'] })
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Backend Registry
|
|
84
|
+
|
|
85
|
+
`StorageBackendRegistry` — global singleton for registering custom backends (Redis, S3, etc.):
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { storageBackendRegistry } from '@x-otto/persistence'
|
|
89
|
+
|
|
90
|
+
storageBackendRegistry.registerPersistence('redis', (opts) => new RedisPersistence(opts))
|
|
91
|
+
const store = createPersistence({ type: 'redis', url: 'redis://...' })
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Built-in backends auto-register at module load time.
|
|
95
|
+
|
|
96
|
+
## Key Files
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
src/
|
|
100
|
+
types.ts # Snapshot, Persistence<T>, Codec, pagination, StorageOptions
|
|
101
|
+
errors.ts # PersistenceError, RemotePersistenceError
|
|
102
|
+
save-document.ts # saveDocument() — envelope constructor
|
|
103
|
+
memory-persistence.ts # MemoryPersistenceBase<S> + MemoryPersistence<T>
|
|
104
|
+
disk-persistence.ts # DiskPersistence<S> — atomic write base
|
|
105
|
+
file-persistence.ts # FilePersistence<T> — Snapshot disk backend
|
|
106
|
+
remote-persistence.ts # RemotePersistence<S> — HTTP client base
|
|
107
|
+
http-persistence.ts # HttpPersistence<T> — Snapshot HTTP backend
|
|
108
|
+
sqlite-persistence.ts # SqlitePersistence — snapshots + change_log tables
|
|
109
|
+
sqlite-db-cache.ts # Shared SQLite connection cache (ref-counted)
|
|
110
|
+
change-log.ts # ChangeLogEntry type
|
|
111
|
+
append-log.ts # AppendLog<E> + memory/file backends + createAppendLog
|
|
112
|
+
sqlite-append-log.ts # SQLite append-log backend
|
|
113
|
+
storage-factory.ts # createPersistence + backend pre-registration
|
|
114
|
+
storage-host.ts # StorageHost — server-side semantic layer
|
|
115
|
+
atomic-write.ts # Atomic file write utility
|
|
116
|
+
panel-state.ts # Extension panel state persistence
|
|
117
|
+
index.ts # Barrel exports
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Dependencies
|
|
121
|
+
|
|
122
|
+
- Internal: `@x-otto/env`
|
|
123
|
+
- External: `better-sqlite3` (SQLite backends)
|
|
124
|
+
- Consumers: `@x-otto/session`, `@x-otto/memory`, `@x-otto/runtime`, `@x-otto/coding`, `@x-otto/service`, `@x-otto/persistence-client`
|
|
125
|
+
|
|
126
|
+
## Testing
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm --filter @x-otto/persistence typecheck
|
|
130
|
+
pnpm --filter @x-otto/persistence build
|
|
131
|
+
pnpm vitest run packages/persistence/tests/
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
18 test files cover all backends CRUD + pagination, AppendLog (truncate / crash-tail repair / concurrency serialization), backend registry, factory, `saveDocument`, `StorageHost`, and change tracking.
|