latticesql 2.3.0 → 3.1.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 +124 -146
- package/dist/cli.js +56850 -20094
- package/dist/index.cjs +47648 -8527
- package/dist/index.d.cts +802 -633
- package/dist/index.d.ts +802 -633
- package/dist/index.js +47080 -8003
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2161,11 +2161,22 @@ Chat threads, files, and secrets are all stored as native Lattice entities.
|
|
|
2161
2161
|
|
|
2162
2162
|
The convergence means you don't need to duplicate entity-context definitions in YAML for the GUI to find rendered files.
|
|
2163
2163
|
|
|
2164
|
-
**Database wizard form (v1.13.2+).** The Postgres connection form (used by Migrate to cloud + the Join-a-
|
|
2165
|
-
|
|
2166
|
-
**Migrate vs. join
|
|
2167
|
-
|
|
2168
|
-
|
|
2164
|
+
**Database wizard form (v1.13.2+).** The Postgres connection form (used by Migrate to cloud + the Join-a-cloud flow) disables browser autocapitalize, autocorrect, and spellcheck on every text input, and trims whitespace on every read. This avoids silent failure modes where macOS Safari / iOS turned a Supabase tenant user `postgres.<ref>` into `Postgres.<ref>` on submit, and where pasted credentials carrying a trailing newline produced opaque "zero-length delimiter identifier" or SCRAM-mismatch errors. `probeCloud` also folds SQLSTATE + `routine` into `result.error` so the GUI's "Unreachable: …" surface is actionable.
|
|
2165
|
+
|
|
2166
|
+
**Migrate vs. join.** The two ways onto a cloud are **Migrate to cloud** (push your
|
|
2167
|
+
local workspace's data into a fresh cloud Postgres; Lattice installs RLS and you
|
|
2168
|
+
become the owner of every migrated row) and **Join a cloud** (connect directly with
|
|
2169
|
+
the scoped credentials the owner handed you — host / port / database / username /
|
|
2170
|
+
password — which _are_ the invite; there is no token to redeem). The
|
|
2171
|
+
`connect-existing` endpoint backs the join: it probes the target as your role,
|
|
2172
|
+
confirms it is a Lattice cloud (RLS installed), and opens it in introspect-only mode.
|
|
2173
|
+
|
|
2174
|
+
**A cloud is just a secured Postgres database.** Migrating to cloud installs the RLS
|
|
2175
|
+
machinery (`installCloudRls` + `enableRlsForTable` per table) and stamps you as owner
|
|
2176
|
+
of the migrated rows — there is no separate "upgrade to team" step and no shared team
|
|
2177
|
+
identity to bootstrap. Membership is purely the set of Postgres roles the owner has
|
|
2178
|
+
provisioned; a member joins by connecting as their own scoped role, and RLS confines
|
|
2179
|
+
them to their own + shared rows.
|
|
2169
2180
|
|
|
2170
2181
|
**Dashboard renders every entity (v1.13.3+).** Previously the dashboard cards filtered through a hardcoded entity list (`meetings`, `people`, `messages`, `projects`, `repositories`, `files`). Installs whose YAML declared different names saw a blank dashboard. Now every first-class entity gets a card; the hardcoded list survives as an ordering preference only.
|
|
2171
2182
|
|
|
@@ -2179,7 +2190,7 @@ The convergence means you don't need to duplicate entity-context definitions in
|
|
|
2179
2190
|
- **Table view** (`#/objects/<entity>`, Advanced mode) — intrinsic columns, `belongsTo` chips, and a column per junction this entity participates in.
|
|
2180
2191
|
- **Detail view** (`#/objects/<entity>/<id>`, Advanced mode) — read mode by default; `Edit` flips cells into inputs (`Save` PATCHes, `Cancel` reverts).
|
|
2181
2192
|
- **Settings** (v2.0+) — opened from the header gear (Database / Lattice / User tabs + the Advanced-mode toggle); the legacy `#/settings/*` hashes still resolve and open the drawer.
|
|
2182
|
-
- **Data Model** (inside **Workspace Settings**, v1.14+) — entity-level graph including the native `files`/`secrets` objects, with a per-entity editor.
|
|
2193
|
+
- **Data Model** (inside **Workspace Settings**, v1.14+) — entity-level graph including the native `files`/`secrets` objects, with a per-entity editor. (Pre-1.14 this was a separate `#/settings/data-model` nav item; that hash still resolves for back-compat.) On a cloud, sharing is per-**row** under Postgres RLS, not per-table — a row's owner sets its visibility (`private` | `everyone`) via the owner-only `lattice_set_row_visibility` SQL function; see [docs/cloud.md](docs/cloud.md).
|
|
2183
2194
|
|
|
2184
2195
|
**Internal tables added on first open**
|
|
2185
2196
|
|
|
@@ -2195,22 +2206,22 @@ These tables are prefixed with `_lattice_gui_` and are hidden from `/api/entitie
|
|
|
2195
2206
|
|
|
2196
2207
|
**HTTP surface** (all routes scoped to `http://127.0.0.1:<port>/api`):
|
|
2197
2208
|
|
|
2198
|
-
| Route
|
|
2199
|
-
|
|
|
2200
|
-
| `/project`
|
|
2201
|
-
| `/entities`
|
|
2202
|
-
| `/graph`
|
|
2203
|
-
| `/tables/:table/rows`
|
|
2204
|
-
| `/tables/:table/rows`
|
|
2205
|
-
| `/tables/:table/rows/:id`
|
|
2206
|
-
| `/tables/:table/rows/:id`
|
|
2207
|
-
| `/tables/:table/rows/:id`
|
|
2208
|
-
| `/tables/:junction/link`
|
|
2209
|
-
| `/tables/:junction/unlink`
|
|
2210
|
-
| `/schema/entities`
|
|
2211
|
-
| `/
|
|
2212
|
-
|
|
2213
|
-
On a cloud
|
|
2209
|
+
| Route | Method | Lattice call |
|
|
2210
|
+
| -------------------------- | ------ | ----------------------------------------------------------- |
|
|
2211
|
+
| `/project` | GET | (config + manifest summary) |
|
|
2212
|
+
| `/entities` | GET | tables + `db.count` per table |
|
|
2213
|
+
| `/graph` | GET | (schema graph for Data Model) |
|
|
2214
|
+
| `/tables/:table/rows` | GET | `db.query(table, …)` |
|
|
2215
|
+
| `/tables/:table/rows` | POST | `db.insert(table, body)` |
|
|
2216
|
+
| `/tables/:table/rows/:id` | GET | `db.get(table, id)` |
|
|
2217
|
+
| `/tables/:table/rows/:id` | PATCH | `db.update(table, id, body)` |
|
|
2218
|
+
| `/tables/:table/rows/:id` | DELETE | `db.delete(table, id)` |
|
|
2219
|
+
| `/tables/:junction/link` | POST | `db.link(junction, body)` |
|
|
2220
|
+
| `/tables/:junction/unlink` | POST | `db.unlink(junction, body)` |
|
|
2221
|
+
| `/schema/entities` | POST | create a new entity/table |
|
|
2222
|
+
| `/cloud/share` | POST | row owner sets a row's visibility (`private` \| `everyone`) |
|
|
2223
|
+
|
|
2224
|
+
On a cloud, you connect as your own scoped Postgres role and **Row-Level Security filters every read and write at the database level** — a row another member hasn't shared with you simply isn't returned by `/tables/:table/rows`, because Postgres itself excludes it. The GUI shows exactly what RLS lets your role see; there is no application-layer allowlist to keep in sync. See [docs/cloud.md](docs/cloud.md).
|
|
2214
2225
|
|
|
2215
2226
|
The server only binds to `127.0.0.1` and has no authentication. See [SECURITY.md](./SECURITY.md) for the threat model — do not expose this port to a non-loopback interface.
|
|
2216
2227
|
|
|
@@ -2249,36 +2260,34 @@ await adoptNativeEntities(db); // merge + label existing files/secrets as native
|
|
|
2249
2260
|
const bindings = await listNativeBindings(db); // [{ entity, tableName, origin }]
|
|
2250
2261
|
```
|
|
2251
2262
|
|
|
2252
|
-
**Machine-local user config at `~/.lattice/` (v1.12+).** A small set of files outside any Lattice DB so a user's identity, encrypted master key, saved cloud-DB credentials
|
|
2263
|
+
**Machine-local user config at `~/.lattice/` (v1.12+).** A small set of files outside any Lattice DB so a user's identity, encrypted master key, and saved cloud-DB credentials survive switching projects. A member's cloud credential is simply their own scoped `postgres://` URL — there are no bearer tokens; the connection string the owner issued is the whole credential:
|
|
2253
2264
|
|
|
2254
2265
|
| File | Purpose |
|
|
2255
2266
|
| ------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
2256
2267
|
| `~/.lattice/master.key` | 32-byte AES-256 master key, auto-generated, `chmod 0600` on POSIX |
|
|
2257
2268
|
| `~/.lattice/identity.json` | `{display_name, email}` — mirrored into the active Lattice's `__lattice_user_identity` row on every open |
|
|
2258
|
-
| `~/.lattice/
|
|
2259
|
-
| `~/.lattice/db-credentials.enc` | AES-GCM-encrypted Postgres URLs keyed by label |
|
|
2269
|
+
| `~/.lattice/db-credentials.enc` | AES-GCM-encrypted Postgres URLs keyed by label (your scoped cloud connection strings) |
|
|
2260
2270
|
|
|
2261
2271
|
The GUI's User Settings view edits `identity.json` directly; the Database Settings page writes saved Postgres URLs into `db-credentials.enc` and rewrites `lattice.config.yml`'s `db:` line to `${LATTICE_DB:<label>}`. The config parser resolves that reference at open time so connection passwords never sit in YAML on disk.
|
|
2262
2272
|
|
|
2263
2273
|
`~/.lattice/preferences.json` (v1.13.8+) holds machine-local UI preferences keyed by name. Currently a single flag `show_system_tables: boolean` (default `false`) — see _Sidebar system-tables toggle (v1.13.8+)_ below.
|
|
2264
2274
|
|
|
2265
|
-
**Information architecture, v1.13.8+.** The GUI treats every database as either Local (single-user SQLite) or Cloud (Postgres
|
|
2275
|
+
**Information architecture, v1.13.8+.** The GUI treats every database as either Local (single-user SQLite) or Cloud (a shared Postgres with one or more members), with the database itself as the first-class concept. A cloud _is_ the set of members who can connect to it — there is no separate "create a team" step, and member management is the cloud's Invite / Members surface (an owner provisions a scoped role; a member joins by connecting as it). Concretely:
|
|
2266
2276
|
|
|
2267
|
-
- **Editable database name** at the top of Database Settings.
|
|
2268
|
-
- **Three-step Create Database wizard.** Opened from the header dropdown's `+ New database` button and from Lattice Settings → Add new database. Step 1: name + Local|Cloud + cloud credentials. Step 2: starter entities
|
|
2277
|
+
- **Editable database name** at the top of Database Settings. A cloud carries no shared name; the name is the operator's own workspace label — so rename always writes a `name:` key into the YAML config (parsed by `parseConfigFile()`, surfaced as `ParsedConfig.name`) and mirrors it into the workspace registry, for both local and cloud configs. Endpoint `POST /api/dbconfig/rename`.
|
|
2278
|
+
- **Three-step Create Database wizard.** Opened from the header dropdown's `+ New database` button and from Lattice Settings → Add new database. Step 1: name + Local|Cloud + cloud credentials. Step 2: starter entities. Step 3: review + create.
|
|
2269
2279
|
- **Header dropdown** shows the friendly database name + a Local|Cloud kind chip + a connectivity dot per row (green = cloud live, yellow = local SQLite, red = cloud disconnected). The `+ New database` button at the bottom opens the wizard.
|
|
2270
2280
|
- **Settings sidebar** is reorganized into Lattice Settings (catalog of all databases this lattice can reach + Add-new entry), Database Settings (renamed from Project Config — editable name header on top, the existing Database panel and cloud-databases list below), Data Model, and User Settings. The legacy `/settings/project-config` route still resolves for back-compat.
|
|
2271
|
-
- **
|
|
2272
|
-
- **New-entity flow** on a cloud-connected database pre-checks a "Share with cloud" box; the share runs best-effort after the entity is created.
|
|
2281
|
+
- **Sharing is per-row, after migration.** On a cloud every row is private to its owner by default; the owner opts individual rows into `everyone` via `/api/cloud/share` (the `lattice_set_row_visibility` SQL function). There is no per-table "share" toggle — RLS works at the row level.
|
|
2273
2282
|
|
|
2274
|
-
**Realtime cloud subscriptions (v1.13.8+).** Cloud Postgres-backed lattices stream changes to every connected GUI in realtime.
|
|
2283
|
+
**Realtime cloud subscriptions (v1.13.8+).** Cloud Postgres-backed lattices stream changes to every connected GUI in realtime. The per-table RLS trigger writes each insert/update/delete to the append-only `__lattice_changes` feed, whose `AFTER INSERT` trigger fires `pg_notify('lattice_changes', …)` with only metadata (table, pk, op) — never row content. The GUI server holds a dedicated `pg.Client` with `LISTEN lattice_changes` and fans payloads out via a Server-Sent Events endpoint; the browser refetches the affected row _through RLS_, so another member's content is never broadcast:
|
|
2275
2284
|
|
|
2276
2285
|
| Route | Method | Description |
|
|
2277
2286
|
| ---------------------- | ------ | -------------------------------------------------------------------------------- |
|
|
2278
2287
|
| `/api/realtime/stream` | GET | SSE stream; `event: state` on connection transitions, `event: change` per NOTIFY |
|
|
2279
2288
|
| `/api/realtime/status` | GET | JSON snapshot of `{ mode: 'local'\|'cloud', state, connected }` |
|
|
2280
2289
|
|
|
2281
|
-
The browser's `EventSource` invalidates the entity cache on every `change` event; connection state drives a colored dot in the topbar (green/yellow/red). SQLite databases are unchanged — LISTEN/NOTIFY is Postgres-only and the broker is skipped on those.
|
|
2290
|
+
The browser's `EventSource` invalidates the entity cache on every `change` event; connection state drives a colored dot in the topbar (green/yellow/red). SQLite databases are unchanged — LISTEN/NOTIFY is Postgres-only and the broker is skipped on those.
|
|
2282
2291
|
|
|
2283
2292
|
**Sidebar system-tables toggle (v1.13.8+).** Internal `__lattice_*` and `_lattice_gui_*` tables are hidden from the sidebar by default. Enable the "Show system tables in sidebar" checkbox in User Settings → Preferences to surface them under a "System" section. Persisted to `~/.lattice/preferences.json`; exposed via `GET`/`POST /api/userconfig/preferences`.
|
|
2284
2293
|
|
|
@@ -2305,8 +2314,9 @@ the library API is unchanged and fully backwards-compatible.
|
|
|
2305
2314
|
revertible via the version history.
|
|
2306
2315
|
- **Inference Aggressiveness** slider tunes how much the assistant extrapolates
|
|
2307
2316
|
(temperature + link liberality + auto-junction/auto-create gating).
|
|
2308
|
-
- Runs on local SQLite and
|
|
2309
|
-
|
|
2317
|
+
- Runs on local SQLite and on any `postgres://` connection, including a Lattice
|
|
2318
|
+
cloud — where it connects as your own scoped role, so its reads and writes are
|
|
2319
|
+
RLS-confined to the rows you may see, exactly like the rest of the GUI.
|
|
2310
2320
|
|
|
2311
2321
|
The same intelligence is exposed as a **first-class library API** (inert without an
|
|
2312
2322
|
LLM client): `organizeSource`, `describeImage`, `crawlUrl`, `enrichKnowledge`, and
|
|
@@ -2316,137 +2326,105 @@ See [docs/assistant.md](docs/assistant.md) for the full guide.
|
|
|
2316
2326
|
|
|
2317
2327
|
---
|
|
2318
2328
|
|
|
2319
|
-
##
|
|
2320
|
-
|
|
2321
|
-
Multi-user cloud-shared Lattice databases on your own Postgres. Bring your own Postgres connection; lattice handles identity (bearer tokens, email-bound invitations), the team membership table, and the sync engine (shared objects + row links + change feed + outbox + replay-guard puller).
|
|
2322
|
-
|
|
2323
|
-
**Bootstrap** (on a fresh cloud — no users yet):
|
|
2324
|
-
|
|
2325
|
-
```bash
|
|
2326
|
-
lattice teams register \
|
|
2327
|
-
--cloud http://localhost:4317 \
|
|
2328
|
-
--email alice@example.com \
|
|
2329
|
-
--name "Alice" \
|
|
2330
|
-
--team-name "Atlas"
|
|
2331
|
-
```
|
|
2332
|
-
|
|
2333
|
-
Atomic: creates the user, the singleton team, the creator membership, and the bearer token in one HTTP call. Prints the token once — save it locally.
|
|
2334
|
-
|
|
2335
|
-
**Invite a teammate by email**:
|
|
2336
|
-
|
|
2337
|
-
```bash
|
|
2338
|
-
lattice teams invite --team Atlas --invitee-email bob@example.com
|
|
2339
|
-
# → prints `latinv_…` token to share OOB with bob@example.com
|
|
2340
|
-
```
|
|
2341
|
-
|
|
2342
|
-
**Join an existing team**:
|
|
2343
|
-
|
|
2344
|
-
```bash
|
|
2345
|
-
lattice teams join \
|
|
2346
|
-
--cloud http://localhost:4317 \
|
|
2347
|
-
--token latinv_… \
|
|
2348
|
-
--email bob@example.com \
|
|
2349
|
-
--name "Bob"
|
|
2350
|
-
```
|
|
2351
|
-
|
|
2352
|
-
The cloud rejects redemption if the caller's claimed email doesn't match the invitation's `invitee_email` (case-insensitive). Sharing an invite token in a public channel is therefore safe — only the addressee can redeem it.
|
|
2353
|
-
|
|
2354
|
-
**Other subcommands** (`lattice teams help` for the full list): `list`, `members`, `leave`, `destroy`, `share`, `unshare`, `shared`, `sync`, `link`, `unlink`, `pull`, `push`, `status`, `dlq`.
|
|
2329
|
+
## Cloud — shared Postgres with Row-Level Security (v3.0+)
|
|
2355
2330
|
|
|
2356
|
-
|
|
2331
|
+
A **Lattice cloud** is a shared Postgres database secured by real Postgres
|
|
2332
|
+
**Row-Level Security**. Several people connect to the same database, each as their
|
|
2333
|
+
own scoped, non-superuser role, and each sees only their own rows plus the rows
|
|
2334
|
+
others have shared. **There is no server** — no HTTP API in front of Postgres, no
|
|
2335
|
+
bearer tokens, no replica, no sync client. The database _is_ the security boundary:
|
|
2336
|
+
a member with full SQL access to their own connection physically cannot read or
|
|
2337
|
+
write another member's rows.
|
|
2357
2338
|
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2339
|
+
A cloud **is** the set of people who can connect to it — there is no separate "team"
|
|
2340
|
+
object and no "enable sharing" step. The DBA only sets up the Postgres database and
|
|
2341
|
+
creates usernames/passwords; Lattice installs the rest with plain SQL (`CREATE ROLE`,
|
|
2342
|
+
`CREATE POLICY`, `FORCE ROW LEVEL SECURITY`, `SECURITY DEFINER` functions). Identity
|
|
2343
|
+
is the Postgres role: policies key on `session_user` / `current_user`, which stays
|
|
2344
|
+
reliable behind a transaction-mode connection pooler.
|
|
2363
2345
|
|
|
2364
|
-
|
|
2346
|
+
SQLite stays single-user and local — RLS is Postgres-only. The bridge from a private
|
|
2347
|
+
local Lattice to a shared one is **migrate**.
|
|
2365
2348
|
|
|
2366
|
-
**
|
|
2349
|
+
**Three flows:**
|
|
2367
2350
|
|
|
2368
|
-
|
|
2351
|
+
- **Migrate** — point a local Lattice at a fresh Postgres; Lattice copies your data
|
|
2352
|
+
in, installs RLS, and makes you the owner of every migrated row.
|
|
2353
|
+
- **Join** — connect directly with the scoped credentials the owner gave you (host /
|
|
2354
|
+
port / database / username / password). **Those credentials _are_ the invite** —
|
|
2355
|
+
there is no token to redeem and no server to sign into.
|
|
2356
|
+
- **Invite** — an owner (whose role holds `CREATEROLE`) provisions a scoped,
|
|
2357
|
+
`NOSUPERUSER` member role and hands the new member that connection blob.
|
|
2369
2358
|
|
|
2370
|
-
**
|
|
2359
|
+
**Sharing is private-by-default.** Every row is owned by whoever wrote it and starts
|
|
2360
|
+
`private`; the owner opts a row into `everyone` (or back to `private`) through the
|
|
2361
|
+
owner-only SQL function:
|
|
2371
2362
|
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
The full architecture, schema, and HTTP surface live in [docs/teams.md](./docs/teams.md).
|
|
2375
|
-
|
|
2376
|
-
---
|
|
2377
|
-
|
|
2378
|
-
## Cloud migration + connection (v1.13+)
|
|
2379
|
-
|
|
2380
|
-
Lattice Teams + the GUI's Database panel now flow through a state machine:
|
|
2381
|
-
|
|
2382
|
-
```
|
|
2383
|
-
LOCAL → CLOUD WORKSPACE (owner | member)
|
|
2384
|
-
(migrate / connect)
|
|
2363
|
+
```sql
|
|
2364
|
+
SELECT lattice_set_row_visibility('items', 'item-42', 'everyone');
|
|
2385
2365
|
```
|
|
2386
2366
|
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
Public API surface (the GUI's `/api/dbconfig/*` routes are thin wrappers):
|
|
2367
|
+
**Library API** — all the cloud helpers import from `latticesql`:
|
|
2390
2368
|
|
|
2391
2369
|
```ts
|
|
2392
2370
|
import {
|
|
2393
2371
|
Lattice,
|
|
2372
|
+
// migrate a local Lattice into a fresh cloud Postgres
|
|
2373
|
+
openTargetLatticeForMigration,
|
|
2394
2374
|
migrateLatticeData,
|
|
2375
|
+
installCloudRls,
|
|
2376
|
+
backfillOwnership,
|
|
2377
|
+
enableRlsForTable,
|
|
2395
2378
|
archiveLocalSqlite,
|
|
2396
|
-
|
|
2379
|
+
// owner provisions / revokes scoped member roles
|
|
2380
|
+
memberRoleName,
|
|
2381
|
+
generateMemberPassword,
|
|
2382
|
+
provisionMemberRole,
|
|
2383
|
+
revokeMemberRole,
|
|
2384
|
+
// sharing + probe
|
|
2385
|
+
setRowVisibility,
|
|
2397
2386
|
probeCloud,
|
|
2398
|
-
TeamsClient,
|
|
2399
2387
|
} from 'latticesql';
|
|
2400
2388
|
|
|
2401
|
-
//
|
|
2402
|
-
const
|
|
2403
|
-
|
|
2404
|
-
const target = await openTargetLatticeForMigration('./lattice.config.yml', cloudUrl, encryptionKey);
|
|
2405
|
-
const result = await migrateLatticeData(source, target);
|
|
2406
|
-
// → { tablesCopied: ['files','items','secrets',...], rowsCopied: 42 }
|
|
2407
|
-
target.close();
|
|
2408
|
-
archiveLocalSqlite('./data/project.db'); // renames to .db.local-bak
|
|
2409
|
-
|
|
2410
|
-
// 2. Probe an arbitrary cloud URL for reachability + team status
|
|
2411
|
-
const probe = await probeCloud('postgres://u:p@host/db');
|
|
2412
|
-
// → { reachable: true, dialect: 'postgres', teamEnabled: false }
|
|
2413
|
-
|
|
2414
|
-
// 3. Connect a fresh project to an existing cloud (auto-redeems if it's a teams DB)
|
|
2415
|
-
const client = new TeamsClient(source);
|
|
2416
|
-
await client.connectToExistingCloud({
|
|
2417
|
-
label: 'atlas',
|
|
2418
|
-
cloudUrl: 'postgres://u:p@host/db',
|
|
2419
|
-
invite_token: 'latinv_...',
|
|
2420
|
-
email: 'bob@example.com',
|
|
2421
|
-
name: 'Bob',
|
|
2422
|
-
});
|
|
2423
|
-
|
|
2424
|
-
// 4. Initialize the workspace member/share machinery on a cloud DB.
|
|
2425
|
-
// The GUI now does this automatically on migrate/connect/open; the
|
|
2426
|
-
// helper remains for programmatic use (idempotent — a no-op if the
|
|
2427
|
-
// cloud is already a workspace).
|
|
2428
|
-
await client.ensureCloudWorkspaceIdentity({
|
|
2429
|
-
label: 'atlas',
|
|
2430
|
-
cloudUrl: 'postgres://u:p@host/db',
|
|
2431
|
-
workspaceName: 'Atlas',
|
|
2432
|
-
email: 'alice@example.com',
|
|
2433
|
-
displayName: 'Alice',
|
|
2434
|
-
});
|
|
2435
|
-
```
|
|
2389
|
+
// Probe a Postgres URL for reachability + whether it's already a Lattice cloud:
|
|
2390
|
+
const probe = await probeCloud('postgres://u:p@host:5432/db');
|
|
2391
|
+
// → { reachable: true, dialect: 'postgres', isCloud: false }
|
|
2436
2392
|
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
|
2446
|
-
|
|
|
2447
|
-
| POST | `/api/dbconfig/
|
|
2448
|
-
|
|
2449
|
-
|
|
2393
|
+
// A member joins by connecting directly as their scoped role — that's all:
|
|
2394
|
+
const db = new Lattice('postgres://lm_bob_a91c:pw@cloud.example.com:5432/app');
|
|
2395
|
+
await db.init();
|
|
2396
|
+
const visible = await db.query('items'); // RLS-filtered to what this role may see
|
|
2397
|
+
```
|
|
2398
|
+
|
|
2399
|
+
**GUI cloud endpoints** (`lattice gui`, localhost-only):
|
|
2400
|
+
|
|
2401
|
+
| Method | Route | Does |
|
|
2402
|
+
| ------ | -------------------------------- | ------------------------------------------------------------------ |
|
|
2403
|
+
| POST | `/api/dbconfig/migrate-to-cloud` | Migrate the active local Lattice into a fresh cloud (you = owner) |
|
|
2404
|
+
| POST | `/api/dbconfig/connect-existing` | Join a cloud directly with scoped credentials (the invite) |
|
|
2405
|
+
| POST | `/api/cloud/invite` | Owner provisions a scoped member role; returns the connection blob |
|
|
2406
|
+
| POST | `/api/cloud/share` | Owner sets a row's visibility (`private` \| `everyone`) |
|
|
2407
|
+
| POST | `/api/cloud/s3-config` | Owner enables S3-backed file bytes for the cloud (secret redacted) |
|
|
2408
|
+
| POST | `/api/cloud/system-prompt` | Owner sets the chat system prompt (owner-only to view/edit) |
|
|
2409
|
+
|
|
2410
|
+
**S3-backed file bytes (opt-in).** By default an uploaded file's bytes live only on
|
|
2411
|
+
the uploader's machine, so other members can see the `files` row but not fetch the
|
|
2412
|
+
content. Enable S3 for the cloud and uploaded bytes also go to S3 under a
|
|
2413
|
+
content-addressed (`<prefix>/<sha256>`) key, so any member who can SELECT the
|
|
2414
|
+
`files` row pulls them in the viewer. Access rides entirely on the files-row RLS;
|
|
2415
|
+
the bucket credential is least-privilege (`GetObject`+`PutObject`, no `ListBucket`),
|
|
2416
|
+
per-member and machine-local. See the caveats in [docs/cloud.md](./docs/cloud.md).
|
|
2417
|
+
|
|
2418
|
+
**Chat system prompt (owner-set).** A cloud owner can set a chat system prompt that
|
|
2419
|
+
is bundled into every member's assistant chat for that workspace. It's owner-only to
|
|
2420
|
+
view and edit (stored in `__lattice_cloud_settings`, reached via owner-gated
|
|
2421
|
+
`SECURITY DEFINER` functions); members never see it through the UI or API.
|
|
2422
|
+
|
|
2423
|
+
Offline editing is preserved as a **client-side local edit queue** that replays on
|
|
2424
|
+
reconnect — it is not tied to any replica or sync server.
|
|
2425
|
+
|
|
2426
|
+
The full architecture, the three flows in detail, the RLS / role model, the S3 +
|
|
2427
|
+
system-prompt designs, and the sharing API live in [docs/cloud.md](./docs/cloud.md).
|
|
2450
2428
|
|
|
2451
2429
|
---
|
|
2452
2430
|
|