@appurist/offlinedb 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 +163 -0
- package/docs/API.md +595 -0
- package/docs/ARCHITECTURE.md +29 -0
- package/docs/DECISIONS.md +20 -0
- package/docs/SQL.md +38 -0
- package/offlinedb.schema.json +10 -0
- package/package.json +39 -0
- package/scripts/apply-schema.mjs +54 -0
- package/scripts/print-schema-sql.mjs +30 -0
- package/src/client.js +587 -0
- package/src/index.js +19 -0
- package/src/neon.js +209 -0
- package/src/schema.js +40 -0
- package/src/sql.js +335 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @appurist/offlinedb
|
|
2
|
+
|
|
3
|
+
Browser-first offline table client for Neon Auth and Postgres Row Level Security.
|
|
4
|
+
|
|
5
|
+
- IndexedDB-friendly local replica abstraction
|
|
6
|
+
- Full local replica model with optional table-filtered sync
|
|
7
|
+
- Optimistic local changes with local ids and server-assigned global ids
|
|
8
|
+
- Neon-oriented HTTP transport contract
|
|
9
|
+
- SQL generators for mutation-log tables, triggers, RLS helpers, and per-table mutation RPCs
|
|
10
|
+
|
|
11
|
+
## Status
|
|
12
|
+
|
|
13
|
+
This repository is the first implementation scaffold for the new `offlinedb` direction.
|
|
14
|
+
It replaces the old client/server split for the Neon path with:
|
|
15
|
+
|
|
16
|
+
- direct authenticated client access
|
|
17
|
+
- Postgres RLS as the security model
|
|
18
|
+
- library-owned mutation RPCs as the consistency model
|
|
19
|
+
- local ids for offline writes and global ids for accepted replicated writes
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add @appurist/offlinedb
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Neon Setup
|
|
28
|
+
|
|
29
|
+
Admin/setup work uses a Postgres connection string through `DATABASE_URL`.
|
|
30
|
+
That connection string is for migrations and schema installation only.
|
|
31
|
+
It must not be used by browser runtime code.
|
|
32
|
+
|
|
33
|
+
All Neon runtime URLs are developer-supplied application configuration.
|
|
34
|
+
The library does not hard-code:
|
|
35
|
+
|
|
36
|
+
- Neon Auth URLs
|
|
37
|
+
- Neon Data API / SQL URLs
|
|
38
|
+
- project-specific endpoints
|
|
39
|
+
- environment-specific connection details
|
|
40
|
+
|
|
41
|
+
This repo includes:
|
|
42
|
+
|
|
43
|
+
- [`offlinedb.schema.json`](./offlinedb.schema.json): synced table config
|
|
44
|
+
- `pnpm run db:print-sql`: print install SQL
|
|
45
|
+
- `pnpm run db:apply`: apply install SQL with `psql`
|
|
46
|
+
- generated metadata tables, triggers, mutation RPCs, and baseline owner RLS
|
|
47
|
+
|
|
48
|
+
The generated install SQL covers database-side `offlinedb` setup only.
|
|
49
|
+
It does not provision Neon projects, branches, Auth, Data API, schema exposure, or CORS.
|
|
50
|
+
|
|
51
|
+
Important RLS note:
|
|
52
|
+
|
|
53
|
+
- generated SQL enables RLS on synced tables
|
|
54
|
+
- generated SQL creates owner-scoped `SELECT`, `INSERT`, `UPDATE`, and `DELETE` policies
|
|
55
|
+
- generated SQL does not yet create public-read, admin-read, admin-write, or app-specific policies automatically
|
|
56
|
+
- grants, schema exposure, and any `SECURITY DEFINER` hardening still need to be reviewed and applied for your app
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
$env:DATABASE_URL="postgresql://..."
|
|
62
|
+
pnpm run db:apply
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The browser runtime should use Neon Auth plus direct authenticated HTTP/Data API calls.
|
|
66
|
+
|
|
67
|
+
## Example Usage - To Do Tasks Example
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
import {
|
|
71
|
+
OfflineDbClient,
|
|
72
|
+
createOdbAuthClient,
|
|
73
|
+
createOdbDataClient,
|
|
74
|
+
createOdbSyncTransport,
|
|
75
|
+
defineTable
|
|
76
|
+
} from "@appurist/offlinedb";
|
|
77
|
+
|
|
78
|
+
const tasks = defineTable({
|
|
79
|
+
name: "tasks",
|
|
80
|
+
primaryKey: "id"
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const auth = createOdbAuthClient({
|
|
84
|
+
baseUrl: appConfig.neonAuthUrl
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const data = createOdbDataClient({
|
|
88
|
+
baseUrl: appConfig.neonDataUrl,
|
|
89
|
+
getAuthToken: async () => appSession.accessToken
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const client = await OfflineDbClient.open({
|
|
93
|
+
persistence: "indexeddb",
|
|
94
|
+
databaseName: "app-cache",
|
|
95
|
+
transport: createOdbSyncTransport({
|
|
96
|
+
dataClient: data
|
|
97
|
+
}),
|
|
98
|
+
tables: [tasks]
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await client.mutate({
|
|
102
|
+
table: "tasks",
|
|
103
|
+
key: "task-1",
|
|
104
|
+
values: {
|
|
105
|
+
title: "Write docs",
|
|
106
|
+
done: false,
|
|
107
|
+
owner_id: "user-1"
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await client.sync();
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`sync()` now represents whole-replica convergence by default:
|
|
115
|
+
|
|
116
|
+
- local pending writes are sent with `localId`
|
|
117
|
+
- the remote side assigns `globalId` values to accepted writes
|
|
118
|
+
- the client advances `lastGlobalId` after applying accepted and remote changes
|
|
119
|
+
- `tables: [...]` is optional and only narrows one sync pass
|
|
120
|
+
|
|
121
|
+
## Public API
|
|
122
|
+
|
|
123
|
+
- `OfflineDbClient`
|
|
124
|
+
- `IndexedDbPersistence`
|
|
125
|
+
- `InMemoryPersistence`
|
|
126
|
+
- `LocalStoragePersistence`
|
|
127
|
+
- `defineTable`
|
|
128
|
+
- `createNeonHttpTransport`
|
|
129
|
+
- `createOdbAuthClient`
|
|
130
|
+
- `createOdbDataClient`
|
|
131
|
+
- `createOdbSyncTransport`
|
|
132
|
+
- `createOfflinedbInstallSql`
|
|
133
|
+
- `createSyncedTableSql`
|
|
134
|
+
|
|
135
|
+
The full API reference lives in [`docs/API.md`](./docs/API.md).
|
|
136
|
+
That document describes:
|
|
137
|
+
|
|
138
|
+
- constructor/open options
|
|
139
|
+
- the persistence contract and the built-in `"indexeddb"`, `"localstorage"`, and `"memory"` selectors
|
|
140
|
+
- local-id/global-id mutation and sync request/response shapes
|
|
141
|
+
- direct Neon Auth and Data API wrappers with `odb*` method names
|
|
142
|
+
- the separation between developer-supplied Neon config and library code
|
|
143
|
+
- setup scripts that install the database-side SQL from `DATABASE_URL`
|
|
144
|
+
- table definition objects and full-replica sync behavior
|
|
145
|
+
- transport expectations
|
|
146
|
+
- SQL generator inputs and outputs
|
|
147
|
+
|
|
148
|
+
## Docs
|
|
149
|
+
|
|
150
|
+
- [`docs/API.md`](./docs/API.md)
|
|
151
|
+
- [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md)
|
|
152
|
+
- [`docs/DECISIONS.md`](./docs/DECISIONS.md)
|
|
153
|
+
- [`docs/SQL.md`](./docs/SQL.md)
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
pnpm test
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|