@serfab/quereus-plugin-sereus 0.8.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 +360 -0
- package/dist/compose-strand.d.ts +84 -0
- package/dist/compose-strand.js +194 -0
- package/dist/compose-strand.js.map +1 -0
- package/dist/connect-browser.d.ts +14 -0
- package/dist/connect-browser.js +45 -0
- package/dist/connect-browser.js.map +1 -0
- package/dist/connect.d.ts +10 -0
- package/dist/connect.js +31 -0
- package/dist/connect.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/parse-config.d.ts +7 -0
- package/dist/parse-config.js +47 -0
- package/dist/parse-config.js.map +1 -0
- package/dist/plugin-browser.d.ts +19 -0
- package/dist/plugin-browser.js +94664 -0
- package/dist/plugin-browser.js.map +7 -0
- package/dist/plugin.d.ts +17 -0
- package/dist/plugin.js +30 -0
- package/dist/plugin.js.map +1 -0
- package/dist/strand-schema.d.ts +30 -0
- package/dist/strand-schema.js +161 -0
- package/dist/strand-schema.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +145 -0
- package/src/compose-strand.ts +314 -0
- package/src/connect-browser.ts +56 -0
- package/src/connect.ts +37 -0
- package/src/index.ts +2 -0
- package/src/parse-config.ts +55 -0
- package/src/plugin-browser.ts +29 -0
- package/src/plugin.ts +39 -0
- package/src/strand-schema.ts +160 -0
- package/src/types.ts +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# @serfab/quereus-plugin-sereus
|
|
2
|
+
|
|
3
|
+
A [Quereus](https://github.com/nicktobey/quereus) plugin that connects a Quereus
|
|
4
|
+
database to a [Sereus](../../docs/architecture.md) strand for SQL access. It
|
|
5
|
+
composes the [@optimystic/quereus-plugin-crypto](https://github.com/nicktobey/optimystic/tree/main/packages/quereus-plugin-crypto)
|
|
6
|
+
and [@optimystic/quereus-plugin-optimystic](https://github.com/nicktobey/optimystic/tree/main/packages/quereus-plugin-optimystic)
|
|
7
|
+
plugins, manages libp2p networking, and optionally applies a sApp schema.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Strand connection**: Connect a Quereus database to a Sereus strand with a single call.
|
|
12
|
+
- **Plugin composition**: Automatically registers the crypto and optimystic plugins.
|
|
13
|
+
- **Node management**: Creates a libp2p node or accepts an injected one (e.g. from a CadreNode).
|
|
14
|
+
- **Schema application**: Wraps DDL in `declare schema App { ... } apply schema App;`.
|
|
15
|
+
- **Two runtimes**: A Node entry (`./plugin`) and a self-contained browser bundle
|
|
16
|
+
(`./plugin-browser`) for Quoomb-web and other browser/worker hosts.
|
|
17
|
+
- **Two entry points**: A plugin-loader-compatible default export and a
|
|
18
|
+
programmatic `connectToStrand()` API.
|
|
19
|
+
|
|
20
|
+
## Artifacts
|
|
21
|
+
|
|
22
|
+
The package ships two plugin artifacts, selected automatically by the consumer's
|
|
23
|
+
environment via the `exports` map:
|
|
24
|
+
|
|
25
|
+
| Artifact | Built by | Transports | Default storage | Use from |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| `dist/plugin.js` | `tsc` | TCP + WebSockets | in-memory / FS | Node (`./plugin`) |
|
|
28
|
+
| `dist/plugin-browser.js` | `esbuild` | WebSockets + circuit-relay | IndexedDB | Browser/worker (`./plugin-browser`) |
|
|
29
|
+
|
|
30
|
+
The browser bundle is a single self-contained ESM file (~2.5 MiB raw, ~550 KiB
|
|
31
|
+
gzipped). It bundles only the TCP-free libp2p surface (`@optimystic/db-p2p/rn`)
|
|
32
|
+
and does **not** import `@quereus/quereus` at runtime — registrations are applied
|
|
33
|
+
against the host-supplied `db`, so it reuses the host's Quereus instance rather
|
|
34
|
+
than instantiating a second one.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @serfab/quereus-plugin-sereus
|
|
40
|
+
# or
|
|
41
|
+
yarn add @serfab/quereus-plugin-sereus
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Using it from Quoomb Web (step by step)
|
|
47
|
+
|
|
48
|
+
[Quoomb Web](../../../quereus/packages/quoomb-web) loads plugins by URL: its
|
|
49
|
+
worker calls `import(url)` and registers the module's default export against the
|
|
50
|
+
live database. To connect Quoomb Web to a strand you need to (1) make the
|
|
51
|
+
**browser bundle** reachable at an importable URL, and (2) give it a strand id
|
|
52
|
+
and at least one **browser-dialable** bootstrap address.
|
|
53
|
+
|
|
54
|
+
### Prerequisites
|
|
55
|
+
|
|
56
|
+
- A **strand id** (UUID) to connect to.
|
|
57
|
+
- For networked use: a libp2p **bootstrap/relay reachable over secure WebSockets**
|
|
58
|
+
(`/wss`) from an `https://` page. Browsers cannot dial raw TCP, and a plain
|
|
59
|
+
`ws://`/`tcp` address will not dial from a TLS origin. WebSockets +
|
|
60
|
+
circuit-relay are the only supported transports in v1.
|
|
61
|
+
- The strand's **sApp schema** (optional — only needed to bootstrap a brand-new
|
|
62
|
+
strand or to expose `App.*` tables before any peer has).
|
|
63
|
+
|
|
64
|
+
### Step 1 — Make the browser bundle importable
|
|
65
|
+
|
|
66
|
+
Pick one of the hosting options below ([Hosting the browser
|
|
67
|
+
bundle](#hosting-the-browser-bundle)). The quickest are:
|
|
68
|
+
|
|
69
|
+
- **Published CDN URL** (recommended once published):
|
|
70
|
+
`https://cdn.jsdelivr.net/npm/@serfab/quereus-plugin-sereus/dist/plugin-browser.js`
|
|
71
|
+
- **Local dev**: copy `dist/plugin-browser.js` into Quoomb Web's `public/` folder
|
|
72
|
+
so it is served same-origin at `http://localhost:5173/plugin-browser.js`.
|
|
73
|
+
|
|
74
|
+
The URL must serve the file with `Content-Type: text/javascript` (or
|
|
75
|
+
`application/javascript`) and CORS that permits the page origin.
|
|
76
|
+
|
|
77
|
+
### Step 2a — Load via the Plugins panel (manual)
|
|
78
|
+
|
|
79
|
+
1. Open Quoomb Web → **Plugins** panel.
|
|
80
|
+
2. Paste the bundle URL into the plugin URL field and install it.
|
|
81
|
+
- The manual installer validates the URL and only accepts **`https://`** (or
|
|
82
|
+
`file://`) ending in `.js`/`.mjs`. A same-origin `http://localhost` URL is
|
|
83
|
+
**rejected here** — use Step 2b (config) for local-dev http, or serve
|
|
84
|
+
Quoomb over https.
|
|
85
|
+
3. Open the plugin's config and set at least:
|
|
86
|
+
- `strand_id` — the strand UUID.
|
|
87
|
+
- `bootstrap_nodes` — comma-separated `/wss` multiaddrs.
|
|
88
|
+
- `schema` — optional sApp DDL.
|
|
89
|
+
4. Run a query, e.g. `select * from App.Message`.
|
|
90
|
+
|
|
91
|
+
### Step 2b — Load via `quoomb.config.json` (autoload)
|
|
92
|
+
|
|
93
|
+
The config/autoload path calls the loader directly and **bypasses the
|
|
94
|
+
https-only check**, so it is the right choice for local `http://localhost`
|
|
95
|
+
during development. In Quoomb Web, open the **Config** modal and import this
|
|
96
|
+
JSON (or set it as `quoomb.config.json`):
|
|
97
|
+
|
|
98
|
+
```jsonc
|
|
99
|
+
{
|
|
100
|
+
"plugins": [
|
|
101
|
+
{
|
|
102
|
+
"source": "https://cdn.jsdelivr.net/npm/@serfab/quereus-plugin-sereus/dist/plugin-browser.js",
|
|
103
|
+
"config": {
|
|
104
|
+
"strand_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
105
|
+
"bootstrap_nodes": "/dns4/relay.example/tcp/443/wss/p2p/Qm...",
|
|
106
|
+
"schema": "table Message (Id integer primary key, Content text not null)"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
"autoload": true
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
With `autoload: true`, the plugin loads on session start and applies the schema.
|
|
115
|
+
|
|
116
|
+
### Step 3 — Query the strand
|
|
117
|
+
|
|
118
|
+
Once loaded, the `optimystic` vtab is the default and `App.*` tables resolve
|
|
119
|
+
against the strand:
|
|
120
|
+
|
|
121
|
+
```sql
|
|
122
|
+
select * from App.Message;
|
|
123
|
+
insert into App.Message (Id, Content) values (1, 'hello strand');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Notes & limitations
|
|
127
|
+
|
|
128
|
+
- **Storage.** When `storage` is not injected, the browser bundle opens a default
|
|
129
|
+
`IndexedDBRawStorage` against an IndexedDB database named
|
|
130
|
+
`sereus-strand-<strandId>`. State survives reload. The plugin treats the
|
|
131
|
+
IndexedDB handle as borrowed and does **not** close it on `shutdown()` — its
|
|
132
|
+
lifecycle is the page/worker.
|
|
133
|
+
- **Networked-only via the loader.** The plugin-loader settings expose the
|
|
134
|
+
`network` transactor; offline/solo `bootstrap` mode is only reachable through
|
|
135
|
+
the programmatic `connectToStrand({ mode: 'bootstrap' })` API.
|
|
136
|
+
- **WebRTC** requires cross-origin isolation (COOP/COEP) and is tracked as a
|
|
137
|
+
follow-up; v1 is WebSockets + circuit-relay only.
|
|
138
|
+
- **Lifecycle.** Quoomb Web's loader keeps only the manifest and discards the
|
|
139
|
+
plugin's returned `shutdown()`, so the libp2p node is torn down with the
|
|
140
|
+
worker rather than on plugin unload.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Hosting the browser bundle
|
|
145
|
+
|
|
146
|
+
The browser bundle is just an ESM file; it can be served from anywhere that
|
|
147
|
+
returns a JavaScript content type with appropriate CORS.
|
|
148
|
+
|
|
149
|
+
### Published package on a CDN (recommended)
|
|
150
|
+
|
|
151
|
+
After `yarn pub:quereus-plugin-sereus` (see [Publishing](#publishing)), the npm
|
|
152
|
+
package is mirrored by the public CDNs, which serve the correct content type and
|
|
153
|
+
CORS automatically:
|
|
154
|
+
|
|
155
|
+
- jsDelivr: `https://cdn.jsdelivr.net/npm/@serfab/quereus-plugin-sereus/dist/plugin-browser.js`
|
|
156
|
+
- jsDelivr (pinned): `https://cdn.jsdelivr.net/npm/@serfab/quereus-plugin-sereus@0.7.1/dist/plugin-browser.js`
|
|
157
|
+
- unpkg: `https://unpkg.com/@serfab/quereus-plugin-sereus/dist/plugin-browser.js`
|
|
158
|
+
|
|
159
|
+
### Self-hosted / same-origin
|
|
160
|
+
|
|
161
|
+
Copy `dist/plugin-browser.js` to any static host (or Quoomb Web's `public/`) and
|
|
162
|
+
reference it by URL. Same-origin hosting sidesteps CORS entirely.
|
|
163
|
+
|
|
164
|
+
### Loading from GitHub
|
|
165
|
+
|
|
166
|
+
Loading the bundle straight from a GitHub repo has a caveat: **`dist/` is
|
|
167
|
+
gitignored**, and `raw.githubusercontent.com` serves files as `text/plain` with
|
|
168
|
+
`X-Content-Type-Options: nosniff`, so the browser refuses to `import()` it as a
|
|
169
|
+
module. Two routes that *do* work:
|
|
170
|
+
|
|
171
|
+
1. **jsDelivr's GitHub endpoint**, which serves repo files with the correct MIME
|
|
172
|
+
type and CORS — but only files that exist at the ref. Since `dist/` is not
|
|
173
|
+
committed, this requires the built bundle to be present at the ref you point
|
|
174
|
+
at (e.g. a CI step that commits `plugin-browser.js` to a `dist`/`gh-pages`
|
|
175
|
+
branch or a tag):
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
https://cdn.jsdelivr.net/gh/gotchoices/sereus@<tag-or-branch>/packages/quereus-plugin-sereus/dist/plugin-browser.js
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. **GitHub Pages**: publish `plugin-browser.js` to a Pages site, which serves it
|
|
182
|
+
with a JavaScript content type and CORS.
|
|
183
|
+
|
|
184
|
+
For most cases the npm-backed CDN URL above is simpler and is the recommended
|
|
185
|
+
GitHub-free hosting path. (Note: GitHub *Release assets* are served as
|
|
186
|
+
`application/octet-stream` and cannot be imported as ESM.)
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Programmatic API
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { Database } from '@quereus/quereus';
|
|
194
|
+
import { connectToStrand } from '@serfab/quereus-plugin-sereus';
|
|
195
|
+
|
|
196
|
+
const db = new Database();
|
|
197
|
+
const strand = await connectToStrand(db, {
|
|
198
|
+
strandId: '550e8400-e29b-41d4-a716-446655440000',
|
|
199
|
+
schema: 'table Message (Id integer primary key, Content text not null)',
|
|
200
|
+
bootstrapNodes: ['/ip4/1.2.3.4/tcp/9100/p2p/QmPeerId'],
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
for await (const row of db.eval('select * from App.Message')) {
|
|
204
|
+
console.log(row);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
await strand.shutdown();
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Plugin-loader (Node)
|
|
211
|
+
|
|
212
|
+
The `./plugin` export is compatible with Quereus plugin-loader:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { Database, registerPlugin } from '@quereus/quereus';
|
|
216
|
+
import sereusPlugin from '@serfab/quereus-plugin-sereus/plugin';
|
|
217
|
+
|
|
218
|
+
const db = new Database();
|
|
219
|
+
const result = await registerPlugin(db, sereusPlugin, {
|
|
220
|
+
strand_id: '550e8400-e29b-41d4-a716-446655440000',
|
|
221
|
+
schema: 'table Message (Id integer primary key, Content text not null)',
|
|
222
|
+
bootstrap_nodes: '/ip4/1.2.3.4/tcp/9100/p2p/QmPeerId',
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
await result.shutdown();
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Bootstrap mode (solo node with persistent storage)
|
|
229
|
+
|
|
230
|
+
For a solo node (e.g. first-launch sApp init, single-host dev) that should apply
|
|
231
|
+
schema and accept DML without peer round trips, set `mode: 'bootstrap'` and pass
|
|
232
|
+
a persistent `IRawStorage`. The same storage instance is wired into both the
|
|
233
|
+
libp2p data path and the optimystic plugin's local transactor, so writes persist
|
|
234
|
+
across restart.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { FileRawStorage } from '@optimystic/db-p2p-storage-fs';
|
|
238
|
+
|
|
239
|
+
const storage = new FileRawStorage('./data/my-strand');
|
|
240
|
+
const strand = await connectToStrand(db, {
|
|
241
|
+
strandId: 'abc',
|
|
242
|
+
mode: 'bootstrap',
|
|
243
|
+
storage,
|
|
244
|
+
schema: 'table Msg (Id integer primary key, Body text not null)',
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The plugin treats `storage` as borrowed: `shutdown()` releases the libp2p node
|
|
249
|
+
and collection factory but does **not** close the storage.
|
|
250
|
+
|
|
251
|
+
### With an injected node
|
|
252
|
+
|
|
253
|
+
When integrating with an existing CadreNode or other libp2p host:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const strand = await connectToStrand(db, {
|
|
257
|
+
strandId: 'abc',
|
|
258
|
+
libp2pNode: existingNode,
|
|
259
|
+
coordinatedRepo: existingRepo,
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The plugin uses the injected node instead of creating one, and will not stop it
|
|
264
|
+
on shutdown.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Configuration
|
|
269
|
+
|
|
270
|
+
### `StrandConnectionOptions` (programmatic API)
|
|
271
|
+
|
|
272
|
+
| Option | Type | Default | Description |
|
|
273
|
+
|---|---|---|---|
|
|
274
|
+
| `strandId` | string | *required* | UUID of the strand to connect to |
|
|
275
|
+
| `bootstrapNodes` | string[] | `[]` | Bootstrap multiaddrs for peer discovery |
|
|
276
|
+
| `schema` | string | — | sApp schema DDL to apply |
|
|
277
|
+
| `sAppId` | string | `'unknown'` | sApp author public key |
|
|
278
|
+
| `sAppVersion` | string | `'1.0.0'` | sApp version |
|
|
279
|
+
| `port` | number | `0` | libp2p listening port (0 = random) |
|
|
280
|
+
| `enableCache` | boolean | `true` | Enable optimystic caching |
|
|
281
|
+
| `fretProfile` | `'edge' \| 'core'` | `'edge'` | FRET profile |
|
|
282
|
+
| `libp2pNode` | Libp2p | — | Inject an existing libp2p node |
|
|
283
|
+
| `coordinatedRepo` | IRepo | — | Required when `libp2pNode` is provided |
|
|
284
|
+
| `mode` | `'bootstrap' \| 'networked'` | `'networked'` | `'bootstrap'` routes through the local transactor (no peer round trips); `'networked'` uses the network transactor |
|
|
285
|
+
| `storage` | IRawStorage | — | Persistent raw storage. Borrowed — not closed on `shutdown()` |
|
|
286
|
+
|
|
287
|
+
### Plugin settings (plugin-loader / Quoomb)
|
|
288
|
+
|
|
289
|
+
| Setting | Type | Default | Description |
|
|
290
|
+
|---|---|---|---|
|
|
291
|
+
| `strand_id` | string | *required* | UUID of the strand |
|
|
292
|
+
| `bootstrap_nodes` | string | `''` | Comma-separated bootstrap multiaddrs |
|
|
293
|
+
| `schema` | string | — | sApp schema DDL |
|
|
294
|
+
| `sapp_id` | string | `'unknown'` | sApp author public key |
|
|
295
|
+
| `sapp_version` | string | `'1.0.0'` | sApp version |
|
|
296
|
+
| `port` | number | `0` | libp2p listening port |
|
|
297
|
+
| `enable_cache` | boolean | `true` | Enable caching |
|
|
298
|
+
| `fret_profile` | string | `'edge'` | FRET profile (`'edge'` or `'core'`) |
|
|
299
|
+
|
|
300
|
+
**Bootstrap multiaddrs.** Browsers can only dial transports reachable from an
|
|
301
|
+
`https://` page. Use `/wss` (or `/dns/.../wss`, or a relay-fronted multiaddr).
|
|
302
|
+
Plain `/tcp/.../ws` over HTTP won't dial from a TLS origin, and raw TCP is
|
|
303
|
+
unavailable in the browser.
|
|
304
|
+
|
|
305
|
+
## Provided functions and modules
|
|
306
|
+
|
|
307
|
+
Registered automatically from the composed plugins:
|
|
308
|
+
|
|
309
|
+
- **Virtual table module**: `optimystic` (set as default vtab)
|
|
310
|
+
- **Functions**: `StampId()`, `digest()`, `sign()`, `verify()`, `randomBytes()`
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Development
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
yarn build # tsc + esbuild (emits dist/plugin.js and dist/plugin-browser.js)
|
|
318
|
+
yarn test # Run tests (unit + e2e projects, plus browser-bundle smoke tests)
|
|
319
|
+
yarn test:e2e # Run only the e2e project (real libp2p + FileRawStorage)
|
|
320
|
+
yarn dev:test # Watch mode
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
`build` runs `tsc -p tsconfig.build.json` (emits `dist/plugin.js`,
|
|
324
|
+
`dist/plugin-browser.js` declarations, and other entries) and then
|
|
325
|
+
`node scripts/build-browser.mjs` (overwrites `dist/plugin-browser.js` with the
|
|
326
|
+
bundled artifact and its sourcemap, and prints raw + gzipped size).
|
|
327
|
+
|
|
328
|
+
The browser-bundle smoke tests (`test/browser-bundle.spec.ts` and
|
|
329
|
+
`test/browser-shape.spec.ts`) run under the `unit` project: they build the
|
|
330
|
+
bundle on demand if missing, then check that the artifact parses as ESM, has no
|
|
331
|
+
Node-only or TCP imports, stays under the size caps, and that its default export
|
|
332
|
+
reaches the IndexedDB layer in a jsdom + `fake-indexeddb` environment.
|
|
333
|
+
|
|
334
|
+
The `e2e` project covers two scenarios over real libp2p + `FileRawStorage`:
|
|
335
|
+
|
|
336
|
+
- `test/e2e/bootstrap.e2e.spec.ts` — solo-node bootstrap mode, including
|
|
337
|
+
cold-restart persistence across the shared storage directory.
|
|
338
|
+
- `test/e2e/networked.e2e.spec.ts` — two in-process peers exchanging strand data
|
|
339
|
+
through a `createLibp2pNode` mesh: cross-peer replication, bidirectional
|
|
340
|
+
convergence, and late-joiner catch-up.
|
|
341
|
+
|
|
342
|
+
## Publishing
|
|
343
|
+
|
|
344
|
+
From the monorepo root:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
yarn pub:quereus-plugin-sereus # clean + build + npm publish --access public
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
This is also included in the aggregate `yarn pub` release step. Publishing emits
|
|
351
|
+
both `dist/plugin.js` and the browser bundle `dist/plugin-browser.js` (both are
|
|
352
|
+
in the package `files`), so the CDN URLs under [Hosting the browser
|
|
353
|
+
bundle](#hosting-the-browser-bundle) resolve immediately after a successful
|
|
354
|
+
publish.
|
|
355
|
+
|
|
356
|
+
## License
|
|
357
|
+
|
|
358
|
+
MIT
|
|
359
|
+
</content>
|
|
360
|
+
</invoke>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Database } from '@quereus/quereus';
|
|
2
|
+
import type { Libp2p } from '@libp2p/interface';
|
|
3
|
+
import type { IRawStorage } from '@optimystic/db-p2p';
|
|
4
|
+
import type { StrandConnectionOptions, SereusPluginResult } from './types.js';
|
|
5
|
+
/** Registration shape shared by the crypto and optimystic plugin results. */
|
|
6
|
+
interface PluginRegistrations {
|
|
7
|
+
vtables?: Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
module: unknown;
|
|
10
|
+
auxData: unknown;
|
|
11
|
+
}>;
|
|
12
|
+
functions?: Array<{
|
|
13
|
+
schema: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
collations?: Array<{
|
|
16
|
+
name: string;
|
|
17
|
+
func: unknown;
|
|
18
|
+
normalizer?: unknown;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Inline equivalent of `@quereus/quereus`'s `registerPlugin` for plugins that
|
|
23
|
+
* only return functions/vtables/collations. Used directly for the optimystic
|
|
24
|
+
* result (so the composition can read `collectionFactory` off the same object),
|
|
25
|
+
* and by the browser crypto strategy to keep the browser bundle from pulling a
|
|
26
|
+
* duplicate `@quereus/quereus` next to the host's instance.
|
|
27
|
+
*/
|
|
28
|
+
export declare function applyRegistrations(db: Database, result: PluginRegistrations): void;
|
|
29
|
+
/** Context passed to the platform's node-creation strategy. */
|
|
30
|
+
export interface CreateNodeContext {
|
|
31
|
+
networkName: string;
|
|
32
|
+
bootstrapNodes: string[];
|
|
33
|
+
fretProfile: 'edge' | 'core';
|
|
34
|
+
/** libp2p listening port (Node TCP). Browser transports ignore it. */
|
|
35
|
+
port: number;
|
|
36
|
+
/** Resolved persistent storage to back the node, if any. */
|
|
37
|
+
storage?: IRawStorage;
|
|
38
|
+
}
|
|
39
|
+
/** Context passed to the platform's storage-resolution strategy. */
|
|
40
|
+
export interface ResolveStorageContext {
|
|
41
|
+
strandId: string;
|
|
42
|
+
resolvedTransactor: string;
|
|
43
|
+
/** The storage the caller passed in `options.storage`, if any. */
|
|
44
|
+
requestedStorage?: IRawStorage;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Platform-specific seams the shared composition delegates to. Everything else
|
|
48
|
+
* (transactor resolution, plugin config, registration, default vtab, hydrate,
|
|
49
|
+
* schema apply, cleanup/shutdown) is identical across Node and browser and lives
|
|
50
|
+
* in {@link composeStrand}.
|
|
51
|
+
*/
|
|
52
|
+
export interface StrandPlatform {
|
|
53
|
+
/**
|
|
54
|
+
* Register the crypto plugin against `db`. Node uses `@quereus/quereus`'s
|
|
55
|
+
* `registerPlugin`; the browser inlines `applyRegistrations` to avoid bundling
|
|
56
|
+
* a second `@quereus/quereus`.
|
|
57
|
+
*/
|
|
58
|
+
registerCrypto(db: Database): void | Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the persistent storage to use. Optional — when omitted the caller's
|
|
61
|
+
* `options.storage` is used verbatim (Node). The browser supplies this to
|
|
62
|
+
* default to IndexedDB so a reload survives.
|
|
63
|
+
*/
|
|
64
|
+
resolveStorage?(ctx: ResolveStorageContext): Promise<IRawStorage | undefined> | IRawStorage | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Create a libp2p node. Called only when no node is injected and the
|
|
67
|
+
* transactor needs one. Node creates a TCP node via `@optimystic/db-p2p`;
|
|
68
|
+
* the browser creates a WebSockets + circuit-relay node via the `/rn` entry.
|
|
69
|
+
* Returns the created node (its `coordinatedRepo` is read by the composition).
|
|
70
|
+
*/
|
|
71
|
+
createNode(ctx: CreateNodeContext): Promise<Libp2p>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Connect a Quereus `Database` to a Sereus strand. This is the single shared
|
|
75
|
+
* SQL-surface composition: `connectToStrand` (Node), `connectToStrandBrowser`
|
|
76
|
+
* (browser), and `cadre-core`'s `StrandDatabase` all flow through here, so the
|
|
77
|
+
* hydrate-before-apply fix and any future schema wiring land in one place.
|
|
78
|
+
*
|
|
79
|
+
* Steps: resolve transactor + storage, register crypto + optimystic plugins,
|
|
80
|
+
* acquire (inject or create) the libp2p node, set optimystic as the default
|
|
81
|
+
* vtab, hydrate the catalog, then apply the sApp schema.
|
|
82
|
+
*/
|
|
83
|
+
export declare function composeStrand(db: Database, options: StrandConnectionOptions, platform: StrandPlatform): Promise<SereusPluginResult>;
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import optimysticPlugin from '@optimystic/quereus-plugin-optimystic/plugin';
|
|
3
|
+
import { STRAND_SCHEMA } from './strand-schema.js';
|
|
4
|
+
const log = debug('sereus:plugin:strand');
|
|
5
|
+
const timing = debug('sereus:plugin:strand:timing');
|
|
6
|
+
/**
|
|
7
|
+
* Inline equivalent of `@quereus/quereus`'s `registerPlugin` for plugins that
|
|
8
|
+
* only return functions/vtables/collations. Used directly for the optimystic
|
|
9
|
+
* result (so the composition can read `collectionFactory` off the same object),
|
|
10
|
+
* and by the browser crypto strategy to keep the browser bundle from pulling a
|
|
11
|
+
* duplicate `@quereus/quereus` next to the host's instance.
|
|
12
|
+
*/
|
|
13
|
+
export function applyRegistrations(db, result) {
|
|
14
|
+
for (const vtable of result.vtables ?? []) {
|
|
15
|
+
db.registerModule(vtable.name, vtable.module, vtable.auxData);
|
|
16
|
+
}
|
|
17
|
+
for (const func of result.functions ?? []) {
|
|
18
|
+
db.registerFunction(func.schema);
|
|
19
|
+
}
|
|
20
|
+
for (const collation of result.collations ?? []) {
|
|
21
|
+
db.registerCollation(collation.name, collation.func, collation.normalizer);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Connect a Quereus `Database` to a Sereus strand. This is the single shared
|
|
26
|
+
* SQL-surface composition: `connectToStrand` (Node), `connectToStrandBrowser`
|
|
27
|
+
* (browser), and `cadre-core`'s `StrandDatabase` all flow through here, so the
|
|
28
|
+
* hydrate-before-apply fix and any future schema wiring land in one place.
|
|
29
|
+
*
|
|
30
|
+
* Steps: resolve transactor + storage, register crypto + optimystic plugins,
|
|
31
|
+
* acquire (inject or create) the libp2p node, set optimystic as the default
|
|
32
|
+
* vtab, hydrate the catalog, then apply the sApp schema.
|
|
33
|
+
*/
|
|
34
|
+
export async function composeStrand(db, options, platform) {
|
|
35
|
+
const { strandId, bootstrapNodes = [], schema, port = 0, enableCache = true, fretProfile = 'edge', mode, } = options;
|
|
36
|
+
// Resolve the transactor. `mode` is the public knob: bootstrap -> local,
|
|
37
|
+
// networked -> network. The legacy `transactor` override (used by unit
|
|
38
|
+
// tests with `'test'`) only applies when `mode` is unspecified.
|
|
39
|
+
let resolvedTransactor;
|
|
40
|
+
if (mode !== undefined) {
|
|
41
|
+
resolvedTransactor = mode === 'bootstrap' ? 'local' : 'network';
|
|
42
|
+
}
|
|
43
|
+
else if (options.transactor !== undefined) {
|
|
44
|
+
resolvedTransactor = options.transactor;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
resolvedTransactor = 'network';
|
|
48
|
+
}
|
|
49
|
+
const networkName = `strand-${strandId}`;
|
|
50
|
+
log('Connecting to strand %s (network: %s, mode=%s, transactor=%s)', strandId, networkName, mode ?? '(default)', resolvedTransactor);
|
|
51
|
+
// Resolve storage. Node passes `options.storage` through; the browser
|
|
52
|
+
// defaults to IndexedDB. The resolved instance feeds BOTH the plugin's
|
|
53
|
+
// bootstrap `rawStorageFactory` and node creation, so it must be decided up
|
|
54
|
+
// front (before pluginConfig is built).
|
|
55
|
+
const storage = platform.resolveStorage
|
|
56
|
+
? await platform.resolveStorage({ strandId, resolvedTransactor, requestedStorage: options.storage })
|
|
57
|
+
: options.storage;
|
|
58
|
+
// 1. Register crypto plugin (digest, sign, verify, etc.)
|
|
59
|
+
await platform.registerCrypto(db);
|
|
60
|
+
log('Registered crypto plugin');
|
|
61
|
+
// 2. Register optimystic plugin with transactor defaults. In local mode with
|
|
62
|
+
// persistent storage, hand the same instance to the plugin so the local
|
|
63
|
+
// transactor persists DML on the host backend (not in-memory).
|
|
64
|
+
const pluginConfig = {
|
|
65
|
+
default_transactor: resolvedTransactor,
|
|
66
|
+
default_key_network: 'libp2p',
|
|
67
|
+
default_network_name: networkName,
|
|
68
|
+
enable_cache: enableCache,
|
|
69
|
+
};
|
|
70
|
+
if (resolvedTransactor === 'local' && storage) {
|
|
71
|
+
pluginConfig.rawStorageFactory = () => storage;
|
|
72
|
+
}
|
|
73
|
+
// The plugin's published signature is `Record<string, SqlValue>` but it
|
|
74
|
+
// also reads `rawStorageFactory` (a function reference) from the same map.
|
|
75
|
+
// Cast through unknown rather than widen the public type.
|
|
76
|
+
const pluginResult = optimysticPlugin(db, pluginConfig);
|
|
77
|
+
applyRegistrations(db, pluginResult);
|
|
78
|
+
log('Registered optimystic vtables and functions');
|
|
79
|
+
const { collectionFactory } = pluginResult;
|
|
80
|
+
let createdNode = null;
|
|
81
|
+
let hydrated;
|
|
82
|
+
try {
|
|
83
|
+
// 3. Acquire the libp2p node. Skip only when this is the unit-test fake
|
|
84
|
+
// transactor with no injected node — every real path needs a node.
|
|
85
|
+
if (resolvedTransactor !== 'test' || options.libp2pNode) {
|
|
86
|
+
let node;
|
|
87
|
+
let coordinatedRepo;
|
|
88
|
+
if (options.libp2pNode) {
|
|
89
|
+
node = options.libp2pNode;
|
|
90
|
+
if (!options.coordinatedRepo) {
|
|
91
|
+
throw new Error('coordinatedRepo is required when libp2pNode is provided');
|
|
92
|
+
}
|
|
93
|
+
coordinatedRepo = options.coordinatedRepo;
|
|
94
|
+
log('Using injected libp2p node');
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const created = await platform.createNode({ networkName, bootstrapNodes, fretProfile, port, storage });
|
|
98
|
+
createdNode = created;
|
|
99
|
+
node = created;
|
|
100
|
+
const repo = created.coordinatedRepo;
|
|
101
|
+
if (!repo) {
|
|
102
|
+
throw new Error('coordinatedRepo not available on created libp2p node');
|
|
103
|
+
}
|
|
104
|
+
coordinatedRepo = repo;
|
|
105
|
+
log('Created libp2p node (port: %d, fretProfile: %s, storage=%s)', port, fretProfile, !!storage);
|
|
106
|
+
}
|
|
107
|
+
collectionFactory.registerLibp2pNode(networkName, node, coordinatedRepo);
|
|
108
|
+
log('Registered libp2p node with collection factory');
|
|
109
|
+
}
|
|
110
|
+
// 4. Set optimystic as default vtab so `declare schema` tables use it.
|
|
111
|
+
db.setDefaultVtabName('optimystic');
|
|
112
|
+
db.setDefaultVtabArgs({
|
|
113
|
+
networkName,
|
|
114
|
+
transactor: resolvedTransactor,
|
|
115
|
+
keyNetwork: 'libp2p',
|
|
116
|
+
});
|
|
117
|
+
log('Set default vtab to optimystic (networkName=%s, transactor=%s)', networkName, resolvedTransactor);
|
|
118
|
+
// 5. Hydrate Quereus's catalog from persisted optimystic vtab schemas
|
|
119
|
+
// BEFORE applying the sApp schema. Without this, a warm restart diffs the
|
|
120
|
+
// wrapped DDL against an empty catalog and re-emits CREATE TABLE / CREATE
|
|
121
|
+
// INDEX for every persisted object — each round-tripping through optimystic
|
|
122
|
+
// storage (the measured ~160s warm-start regression). No-op on first launch.
|
|
123
|
+
const t0 = performance.now();
|
|
124
|
+
hydrated = await pluginResult.hydrate(db);
|
|
125
|
+
timing('[strand:%s] hydrate: %dms (tables=%d, indexes=%d)', strandId, Math.round(performance.now() - t0), hydrated.tables, hydrated.indexes);
|
|
126
|
+
log('Hydrated catalog for strand %s (tables=%d, indexes=%d)', strandId, hydrated.tables, hydrated.indexes);
|
|
127
|
+
// 6. Apply the strand membership/RBAC schema (`schemas/strand.qsql`,
|
|
128
|
+
// embedded as STRAND_SCHEMA) UNCONDITIONALLY — every strand has membership
|
|
129
|
+
// semantics whether or not an sApp schema is supplied. There are no
|
|
130
|
+
// cross-schema references between `Strand` and `App`, so order is
|
|
131
|
+
// irrelevant; apply `Strand` first for clarity. Because this runs AFTER
|
|
132
|
+
// hydrate, a warm restart diffs the membership DDL against the already-
|
|
133
|
+
// hydrated catalog and re-emits nothing (same fix as the sApp apply).
|
|
134
|
+
//
|
|
135
|
+
// This ticket only makes the tables present and their constraints active;
|
|
136
|
+
// nothing here writes membership rows. Founder bootstrap (Header, founding
|
|
137
|
+
// Authority/Member, invite/peer flows) is owned by the lifecycle ticket
|
|
138
|
+
// `strand-membership-lifecycle-population`.
|
|
139
|
+
log('Applying Strand membership schema for strand %s', strandId);
|
|
140
|
+
await db.exec(`
|
|
141
|
+
declare schema Strand {
|
|
142
|
+
${STRAND_SCHEMA}
|
|
143
|
+
}
|
|
144
|
+
apply schema Strand;
|
|
145
|
+
`);
|
|
146
|
+
log('Strand membership schema applied');
|
|
147
|
+
// 7. Apply the sApp schema, if provided.
|
|
148
|
+
//
|
|
149
|
+
// SEAM: this and the Strand apply above are the single composition point
|
|
150
|
+
// where strand-level declarative DDL is applied. Keep new schema wiring
|
|
151
|
+
// here so it stays a one-location edit across Node, browser, and cadre-core.
|
|
152
|
+
if (schema) {
|
|
153
|
+
log('Applying sApp schema for strand %s', strandId);
|
|
154
|
+
await db.exec(`
|
|
155
|
+
declare schema App {
|
|
156
|
+
${schema}
|
|
157
|
+
}
|
|
158
|
+
apply schema App;
|
|
159
|
+
`);
|
|
160
|
+
log('sApp schema applied');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// Clean up resources if setup fails after partial initialization.
|
|
165
|
+
await collectionFactory.shutdown();
|
|
166
|
+
if (createdNode) {
|
|
167
|
+
await createdNode.stop();
|
|
168
|
+
}
|
|
169
|
+
throw err;
|
|
170
|
+
}
|
|
171
|
+
// 8. Return result with hydrate counts + shutdown handler. `shutdown` tears
|
|
172
|
+
// down the collection factory, and `collectionFactory.shutdown()` stops EVERY
|
|
173
|
+
// node registered with it — including an injected one (registered via
|
|
174
|
+
// `registerLibp2pNode`). So an injected node IS stopped on `shutdown`; the
|
|
175
|
+
// `createdNode` guard below only avoids a redundant second `stop()` on a node
|
|
176
|
+
// we created ourselves, it is not what spares an injected node. A caller that
|
|
177
|
+
// needs an injected node to outlive `shutdown` must re-create it (cadre-core's
|
|
178
|
+
// `StrandInstanceManager` instead re-stops it, which is idempotent).
|
|
179
|
+
return {
|
|
180
|
+
vtables: [],
|
|
181
|
+
functions: [],
|
|
182
|
+
collations: [],
|
|
183
|
+
hydrated,
|
|
184
|
+
async shutdown() {
|
|
185
|
+
log('Shutting down strand connection %s', strandId);
|
|
186
|
+
await collectionFactory.shutdown();
|
|
187
|
+
if (createdNode) {
|
|
188
|
+
await createdNode.stop();
|
|
189
|
+
}
|
|
190
|
+
log('Strand connection %s shut down', strandId);
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=compose-strand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,gBAAgB,MAAM,8CAA8C,CAAC;AAK5E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,GAAG,GAAG,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,6BAA6B,CAAC,CAAC;AAwCpD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAY,EAAE,MAA2B;IAC3E,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC3C,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QAC3C,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAa,CAAC,CAAC;IACzC,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QACjD,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAW,EAAE,SAAS,CAAC,UAAiB,CAAC,CAAC;IAC1F,CAAC;AACF,CAAC;AAiDD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,EAAY,EACZ,OAAgC,EAChC,QAAwB;IAExB,MAAM,EACL,QAAQ,EACR,cAAc,GAAG,EAAE,EACnB,MAAM,EACN,IAAI,GAAG,CAAC,EACR,WAAW,GAAG,IAAI,EAClB,WAAW,GAAG,MAAM,EACpB,IAAI,GACJ,GAAG,OAAO,CAAC;IAEZ,yEAAyE;IACzE,uEAAuE;IACvE,gEAAgE;IAChE,IAAI,kBAA0B,CAAC;IAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACxB,kBAAkB,GAAG,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,CAAC;SAAM,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7C,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;IACzC,CAAC;SAAM,CAAC;QACP,kBAAkB,GAAG,SAAS,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,QAAQ,EAAE,CAAC;IACzC,GAAG,CAAC,+DAA+D,EAClE,QAAQ,EAAE,WAAW,EAAE,IAAI,IAAI,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAEjE,sEAAsE;IACtE,uEAAuE;IACvE,4EAA4E;IAC5E,wCAAwC;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc;QACtC,CAAC,CAAC,MAAM,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACpG,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAEnB,yDAAyD;IACzD,MAAM,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IAClC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAEhC,6EAA6E;IAC7E,wEAAwE;IACxE,+DAA+D;IAC/D,MAAM,YAAY,GAA4B;QAC7C,kBAAkB,EAAE,kBAAkB;QACtC,mBAAmB,EAAE,QAAQ;QAC7B,oBAAoB,EAAE,WAAW;QACjC,YAAY,EAAE,WAAW;KACzB,CAAC;IACF,IAAI,kBAAkB,KAAK,OAAO,IAAI,OAAO,EAAE,CAAC;QAC/C,YAAY,CAAC,iBAAiB,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC;IAChD,CAAC;IACD,wEAAwE;IACxE,2EAA2E;IAC3E,0DAA0D;IAC1D,MAAM,YAAY,GAAG,gBAAgB,CACpC,EAAE,EACF,YAAiE,CACvC,CAAC;IAC5B,kBAAkB,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IACrC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAEnD,MAAM,EAAE,iBAAiB,EAAE,GAAG,YAAY,CAAC;IAE3C,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,QAAyD,CAAC;IAE9D,IAAI,CAAC;QACJ,wEAAwE;QACxE,mEAAmE;QACnE,IAAI,kBAAkB,KAAK,MAAM,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACzD,IAAI,IAAY,CAAC;YACjB,IAAI,eAAsB,CAAC;YAE3B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACxB,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;gBAC1B,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;oBAC9B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;gBAC5E,CAAC;gBACD,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;gBAC1C,GAAG,CAAC,4BAA4B,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACP,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;gBACvG,WAAW,GAAG,OAAO,CAAC;gBACtB,IAAI,GAAG,OAAO,CAAC;gBACf,MAAM,IAAI,GAAI,OAA8B,CAAC,eAAe,CAAC;gBAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;oBACX,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;gBACzE,CAAC;gBACD,eAAe,GAAG,IAAI,CAAC;gBACvB,GAAG,CAAC,6DAA6D,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAClG,CAAC;YAED,iBAAiB,CAAC,kBAAkB,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;YACzE,GAAG,CAAC,gDAAgD,CAAC,CAAC;QACvD,CAAC;QAED,uEAAuE;QACvE,EAAE,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;QACpC,EAAE,CAAC,kBAAkB,CAAC;YACrB,WAAW;YACX,UAAU,EAAE,kBAAkB;YAC9B,UAAU,EAAE,QAAQ;SACpB,CAAC,CAAC;QACH,GAAG,CAAC,gEAAgE,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;QAEvG,sEAAsE;QACtE,0EAA0E;QAC1E,0EAA0E;QAC1E,4EAA4E;QAC5E,6EAA6E;QAC7E,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC7B,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,mDAAmD,EACzD,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClF,GAAG,CAAC,wDAAwD,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE3G,qEAAqE;QACrE,2EAA2E;QAC3E,oEAAoE;QACpE,kEAAkE;QAClE,wEAAwE;QACxE,wEAAwE;QACxE,sEAAsE;QACtE,EAAE;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,wEAAwE;QACxE,4CAA4C;QAC5C,GAAG,CAAC,iDAAiD,EAAE,QAAQ,CAAC,CAAC;QACjE,MAAM,EAAE,CAAC,IAAI,CAAC;;MAEV,aAAa;;;GAGhB,CAAC,CAAC;QACH,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAExC,yCAAyC;QACzC,EAAE;QACF,yEAAyE;QACzE,wEAAwE;QACxE,6EAA6E;QAC7E,IAAI,MAAM,EAAE,CAAC;YACZ,GAAG,CAAC,oCAAoC,EAAE,QAAQ,CAAC,CAAC;YACpD,MAAM,EAAE,CAAC,IAAI,CAAC;;OAEV,MAAM;;;IAGT,CAAC,CAAC;YACH,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC5B,CAAC;IACF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,kEAAkE;QAClE,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,WAAW,EAAE,CAAC;YACjB,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QACD,MAAM,GAAG,CAAC;IACX,CAAC;IAED,4EAA4E;IAC5E,8EAA8E;IAC9E,sEAAsE;IACtE,2EAA2E;IAC3E,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,qEAAqE;IACrE,OAAO;QACN,OAAO,EAAE,EAAE;QACX,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,EAAE;QACd,QAAQ;QACR,KAAK,CAAC,QAAQ;YACb,GAAG,CAAC,oCAAoC,EAAE,QAAQ,CAAC,CAAC;YACpD,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC;YACnC,IAAI,WAAW,EAAE,CAAC;gBACjB,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;YAC1B,CAAC;YACD,GAAG,CAAC,gCAAgC,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Database } from '@quereus/quereus';
|
|
2
|
+
import type { StrandConnectionOptions, SereusPluginResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Connect a Quereus Database to a Sereus strand from a browser/worker.
|
|
5
|
+
*
|
|
6
|
+
* Thin adapter over the shared {@link composeStrand} composition, supplying the
|
|
7
|
+
* browser platform seams:
|
|
8
|
+
* - crypto registered inline (no runtime `@quereus/quereus` import, so the
|
|
9
|
+
* bundle does not duplicate the host's instance),
|
|
10
|
+
* - storage defaulting to `IndexedDBRawStorage` keyed by `sereus-strand-<id>`,
|
|
11
|
+
* - a node created via the TCP-free `@optimystic/db-p2p/rn` entry with explicit
|
|
12
|
+
* `webSockets()` + `circuitRelayTransport()` transports.
|
|
13
|
+
*/
|
|
14
|
+
export declare function connectToStrandBrowser(db: Database, options: StrandConnectionOptions): Promise<SereusPluginResult>;
|