@jcbuisson/express-x-plugins 4.0.4 → 4.0.5
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 +34 -14
- package/package.json +1 -1
- package/src/electric-client-plugin.mjs +2 -12
package/README.md
CHANGED
|
@@ -1,23 +1,43 @@
|
|
|
1
|
-
# express-x-
|
|
1
|
+
# express-x-plugins
|
|
2
|
+
|
|
3
|
+
Currently includes:
|
|
4
|
+
|
|
5
|
+
- a plugin which preserves room membership and socket data across page reloads
|
|
6
|
+
- a plugin integrating ElectricSQL sync engine into express-x, which greatly simplifies relational database
|
|
7
|
+
access and provides powerful local-first features
|
|
2
8
|
|
|
3
|
-
The smallest useful ElectricSQL integration for Express-X. Express-X handles
|
|
4
|
-
authorized PostgreSQL mutations; Electric's Shape API streams those changes to
|
|
5
|
-
clients: Electric is the sync engine.
|
|
6
9
|
|
|
7
10
|
## Install
|
|
8
11
|
|
|
9
12
|
```sh
|
|
10
|
-
npm install @jcbuisson/express-x-
|
|
13
|
+
npm install @jcbuisson/express-x-plugins
|
|
11
14
|
```
|
|
12
15
|
|
|
13
|
-
This server-only installation does not install the browser Electric client or RxJS.
|
|
14
16
|
|
|
15
|
-
##
|
|
17
|
+
## Reload plugin
|
|
18
|
+
|
|
19
|
+
### Server
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { reloadPlugin } from '@jcbuisson/express-x-plugins/reload-server'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Local-first Postgres plugin
|
|
27
|
+
|
|
28
|
+
The smallest useful ElectricSQL integration for Express-X. Express-X handles authorized PostgreSQL mutations;
|
|
29
|
+
Electric's Shape API streams those changes to clients: Electric is the sync engine.
|
|
30
|
+
|
|
31
|
+
### Server
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install pg
|
|
35
|
+
```
|
|
16
36
|
|
|
17
37
|
```js
|
|
18
38
|
import { Pool } from 'pg'
|
|
19
|
-
import { expressX } from '@jcbuisson/express-x'
|
|
20
|
-
import { electricOfflinePlugin } from '@jcbuisson/express-x-electric'
|
|
39
|
+
import { expressX } from '@jcbuisson/express-x/server'
|
|
40
|
+
import { electricOfflinePlugin } from '@jcbuisson/express-x-plugins/electric-server'
|
|
21
41
|
|
|
22
42
|
const app = expressX()
|
|
23
43
|
const db = new Pool({ connectionString: process.env.DATABASE_URL })
|
|
@@ -49,16 +69,16 @@ Mutation results remain `[value, meta]` tuples for compatibility. `meta.txid`
|
|
|
49
69
|
contains `pg_current_xact_id()` and can be passed to an Electric-aware client to
|
|
50
70
|
wait for the matching transaction in its Shape stream.
|
|
51
71
|
|
|
52
|
-
|
|
72
|
+
### Client
|
|
53
73
|
|
|
54
74
|
Install the optional client dependencies in the browser application:
|
|
55
75
|
|
|
56
76
|
```sh
|
|
57
|
-
npm install @
|
|
77
|
+
npm install @electric-sql/client rxjs
|
|
58
78
|
```
|
|
59
79
|
|
|
60
80
|
```js
|
|
61
|
-
import { electricClientPlugin } from '@jcbuisson/express-x-electric
|
|
81
|
+
import { electricClientPlugin } from '@jcbuisson/express-x-plugins/electric-client'
|
|
62
82
|
|
|
63
83
|
app.configure(electricClientPlugin, {
|
|
64
84
|
shapePath: '/electric/v1/shape',
|
|
@@ -93,7 +113,7 @@ Object filters use parameterized Electric Shape predicates. Exact values,
|
|
|
93
113
|
All Electric cursor parameters are forwarded. The client cannot override the
|
|
94
114
|
configured table, and Electric source credentials stay server-side.
|
|
95
115
|
|
|
96
|
-
|
|
116
|
+
### Model configuration
|
|
97
117
|
|
|
98
118
|
Models may be strings (table, service name, and default `uid` key) or objects:
|
|
99
119
|
|
|
@@ -108,7 +128,7 @@ Requires Node 18+ for the built-in Fetch API. The PostgreSQL client only needs a
|
|
|
108
128
|
`query(sql, values)` method; a `pg.Pool` is recommended so each mutation and its
|
|
109
129
|
transaction ID are captured in the same transaction.
|
|
110
130
|
|
|
111
|
-
|
|
131
|
+
### Run Electric from Docker
|
|
112
132
|
|
|
113
133
|
A local install of the Electric sync engine requires Elixir and Erlang; it is simpler to use a pre-built Docker image.
|
|
114
134
|
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import { getCurrentScope, onScopeDispose, ref } from 'vue'
|
|
|
10
10
|
* electricClientPlugin(app)
|
|
11
11
|
* const todo = app.createElectricModel('todos')
|
|
12
12
|
* todo.getObservable({ completed: false }).subscribe(...)
|
|
13
|
+
* const completedTodos = await todo.findMany({ completed: false })
|
|
13
14
|
*/
|
|
14
15
|
export function electricClientPlugin(app, options = {}) {
|
|
15
16
|
const shapePath = options.shapePath ?? '/electric/v1/shape'
|
|
@@ -47,13 +48,6 @@ export function electricClientPlugin(app, options = {}) {
|
|
|
47
48
|
})
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
function getVueRef(where = {}) {
|
|
51
|
-
const value = ref([])
|
|
52
|
-
const subscription = getObservable(where).subscribe(rows => { value.value = rows })
|
|
53
|
-
if (getCurrentScope()) onScopeDispose(() => subscription.unsubscribe())
|
|
54
|
-
return value
|
|
55
|
-
}
|
|
56
|
-
|
|
57
51
|
function findMany(where = {}) {
|
|
58
52
|
const observable = getObservable(where)
|
|
59
53
|
if (!getCurrentScope()) return firstValueFrom(observable)
|
|
@@ -66,10 +60,6 @@ export function electricClientPlugin(app, options = {}) {
|
|
|
66
60
|
return firstValueFrom(observable.pipe(takeUntil(scopeDisposed)))
|
|
67
61
|
}
|
|
68
62
|
|
|
69
|
-
function findUnique(where = {}) {
|
|
70
|
-
return findMany(where).then(rows => rows[0] ?? null)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
63
|
async function create(data) {
|
|
74
64
|
assertPlainObject(data, 'mutation data')
|
|
75
65
|
const uid = globalThis.crypto?.randomUUID?.()
|
|
@@ -89,7 +79,7 @@ export function electricClientPlugin(app, options = {}) {
|
|
|
89
79
|
return value
|
|
90
80
|
}
|
|
91
81
|
|
|
92
|
-
return { getObservable,
|
|
82
|
+
return { getObservable, findMany, create, update, remove }
|
|
93
83
|
}
|
|
94
84
|
|
|
95
85
|
return Object.assign(app, { createElectricModel })
|