latticesql 1.11.0 → 1.13.1
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 +167 -6
- package/dist/cli.js +5572 -387
- package/dist/index.cjs +1529 -92
- package/dist/index.d.cts +721 -3
- package/dist/index.d.ts +721 -3
- package/dist/index.js +1508 -85
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2066,12 +2066,21 @@ npx lattice gui --config ./lattice.config.yml --output ./context --port 4317
|
|
|
2066
2066
|
|
|
2067
2067
|
**Options**
|
|
2068
2068
|
|
|
2069
|
-
| Flag | Default | Description
|
|
2070
|
-
| --------------------- | ---------------------- |
|
|
2071
|
-
| `--config, -c <path>` | `./lattice.config.yml` | Path to the config file
|
|
2072
|
-
| `--output <dir>` |
|
|
2073
|
-
| `--port <number>` | `4317` | Localhost port; auto-increments when the port is busy
|
|
2074
|
-
| `--no-open` | off | Print the URL without opening a browser
|
|
2069
|
+
| Flag | Default | Description |
|
|
2070
|
+
| --------------------- | ---------------------- | -------------------------------------------------------- |
|
|
2071
|
+
| `--config, -c <path>` | `./lattice.config.yml` | Path to the config file |
|
|
2072
|
+
| `--output <dir>` | (auto-detected) | Output directory containing rendered context — see below |
|
|
2073
|
+
| `--port <number>` | `4317` | Localhost port; auto-increments when the port is busy |
|
|
2074
|
+
| `--no-open` | off | Print the URL without opening a browser |
|
|
2075
|
+
|
|
2076
|
+
**Output-directory auto-detection (v1.13.1+).** When `--output` is not passed explicitly, the GUI probes `./context`, `.`, and `./generated` in order and uses the first directory containing a `.lattice/manifest.json` (announced via a one-line `auto-detected rendered context at "<dir>"` log on stdout). Projects whose `lattice render` writes into the project root no longer need to pass `--output .` every time. An explicit `--output` is always honoured.
|
|
2077
|
+
|
|
2078
|
+
**Entity-context discovery (v1.13.1+).** The Database panel's row-context viewer reads entity contexts from two layered sources so it works regardless of how you register them:
|
|
2079
|
+
|
|
2080
|
+
1. **Live Lattice schema** — anything declared in `lattice.config.yml` or added programmatically via `db.defineEntityContext()` against the active Lattice. Exposed via the new public `Lattice.entityContexts()` accessor.
|
|
2081
|
+
2. **Render manifest fallback** — when a table has no schema-registered entity context but the on-disk `.lattice/manifest.json` names it (typical for projects that register entity contexts in a JS / TS module like `lattice.schema.mjs` that the GUI process never imports), the GUI derives the row → slug mapping heuristically from `row.slug` / `row.id` / `row.name` and surfaces the rendered files anyway.
|
|
2082
|
+
|
|
2083
|
+
The convergence means you don't need to duplicate entity-context definitions in YAML for the GUI to find rendered files.
|
|
2075
2084
|
|
|
2076
2085
|
**Views**
|
|
2077
2086
|
|
|
@@ -2109,6 +2118,158 @@ These tables are prefixed with `_lattice_gui_` and are hidden from `/api/entitie
|
|
|
2109
2118
|
|
|
2110
2119
|
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.
|
|
2111
2120
|
|
|
2121
|
+
**Native `secrets` and `files` entities (v1.12+).** Every Lattice opened by `lattice gui` automatically registers two framework-shipped tables before `init()`:
|
|
2122
|
+
|
|
2123
|
+
| Table | Shape |
|
|
2124
|
+
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2125
|
+
| `secrets` | `id, name, kind, value (encrypted), description, created_at, updated_at, deleted_at` |
|
|
2126
|
+
| `files` | `id, original_name, mime, size_bytes, sha256, blob_path, extraction_status, extracted_text, description, …` (superset of any legacy `path`/`kind` columns) |
|
|
2127
|
+
|
|
2128
|
+
`secrets.value` is encrypted at rest via a new `TableDefinition.encrypted?: { columns: string[] }` field that extends the existing entity-context encryption to plain `define()` tables. The encryption master key resolves from `LATTICE_ENCRYPTION_KEY` (env) or `~/.lattice/master.key` (auto-generated, `chmod 0600` on POSIX). The companion helper `attachBlob(srcPath, latticeRoot)` writes any file into a content-addressed store at `<root>/data/blobs/<sha256>` and returns metadata suitable for a `files` row.
|
|
2129
|
+
|
|
2130
|
+
You can also register the native entities programmatically when opening a Lattice outside the GUI:
|
|
2131
|
+
|
|
2132
|
+
```ts
|
|
2133
|
+
import { Lattice } from 'latticesql';
|
|
2134
|
+
import { registerNativeEntities } from 'latticesql/framework/native-entities';
|
|
2135
|
+
|
|
2136
|
+
const db = new Lattice(
|
|
2137
|
+
{ config: './lattice.config.yml' },
|
|
2138
|
+
{ encryptionKey: process.env.LATTICE_ENCRYPTION_KEY },
|
|
2139
|
+
);
|
|
2140
|
+
registerNativeEntities(db);
|
|
2141
|
+
await db.init();
|
|
2142
|
+
```
|
|
2143
|
+
|
|
2144
|
+
**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, and per-team bearer tokens survive switching projects:
|
|
2145
|
+
|
|
2146
|
+
| File | Purpose |
|
|
2147
|
+
| ------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
2148
|
+
| `~/.lattice/master.key` | 32-byte AES-256 master key, auto-generated, `chmod 0600` on POSIX |
|
|
2149
|
+
| `~/.lattice/identity.json` | `{display_name, email}` — mirrored into the active Lattice's `__lattice_user_identity` row on every open |
|
|
2150
|
+
| `~/.lattice/keys/<label>.token` | Per-joined-team bearer tokens (`chmod 0600`) |
|
|
2151
|
+
| `~/.lattice/db-credentials.enc` | AES-GCM-encrypted Postgres URLs keyed by label |
|
|
2152
|
+
|
|
2153
|
+
The GUI's User Config view edits `identity.json` directly; the Project Config "Database" panel 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.
|
|
2154
|
+
|
|
2155
|
+
---
|
|
2156
|
+
|
|
2157
|
+
## CLI — `lattice teams` (v1.12+)
|
|
2158
|
+
|
|
2159
|
+
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).
|
|
2160
|
+
|
|
2161
|
+
**Bootstrap** (on a fresh cloud — no users yet):
|
|
2162
|
+
|
|
2163
|
+
```bash
|
|
2164
|
+
lattice teams register \
|
|
2165
|
+
--cloud http://localhost:4317 \
|
|
2166
|
+
--email alice@example.com \
|
|
2167
|
+
--name "Alice" \
|
|
2168
|
+
--team-name "Atlas"
|
|
2169
|
+
```
|
|
2170
|
+
|
|
2171
|
+
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.
|
|
2172
|
+
|
|
2173
|
+
**Invite a teammate by email**:
|
|
2174
|
+
|
|
2175
|
+
```bash
|
|
2176
|
+
lattice teams invite --team Atlas --invitee-email bob@example.com
|
|
2177
|
+
# → prints `latinv_…` token to share OOB with bob@example.com
|
|
2178
|
+
```
|
|
2179
|
+
|
|
2180
|
+
**Join an existing team**:
|
|
2181
|
+
|
|
2182
|
+
```bash
|
|
2183
|
+
lattice teams join \
|
|
2184
|
+
--cloud http://localhost:4317 \
|
|
2185
|
+
--token latinv_… \
|
|
2186
|
+
--email bob@example.com \
|
|
2187
|
+
--name "Bob"
|
|
2188
|
+
```
|
|
2189
|
+
|
|
2190
|
+
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.
|
|
2191
|
+
|
|
2192
|
+
**Other subcommands** (`lattice teams help` for the full list): `list`, `members`, `leave`, `destroy`, `share`, `unshare`, `shared`, `sync`, `link`, `unlink`, `pull`, `push`, `status`.
|
|
2193
|
+
|
|
2194
|
+
**Same flows from the GUI.** The local `lattice gui` Project Config view drives the entire teams lifecycle — create / join, invite by email, share tables, link rows, see sync status. Identity (display name + email) comes from `~/.lattice/identity.json` and is prefilled in every modal.
|
|
2195
|
+
|
|
2196
|
+
**Cloud server mode**: `lattice gui --team-cloud` boots the same binary as a cloud server. It exposes the bearer-token-gated `/api/team*` endpoints + the `/objects`/`/changes`/`/rows`/`/links` sync routes, and disables the local dev-tool surface (table viewer, CRUD endpoints, register-and-create modal).
|
|
2197
|
+
|
|
2198
|
+
The full architecture, schema, and HTTP surface live in [docs/teams.md](./docs/teams.md).
|
|
2199
|
+
|
|
2200
|
+
---
|
|
2201
|
+
|
|
2202
|
+
## Cloud migration + connection (v1.13+)
|
|
2203
|
+
|
|
2204
|
+
Lattice Teams + the GUI's Database panel now flow through a state machine:
|
|
2205
|
+
|
|
2206
|
+
```
|
|
2207
|
+
LOCAL → CLOUD CONNECTED → TEAM CLOUD
|
|
2208
|
+
(migrate) (upgrade)
|
|
2209
|
+
```
|
|
2210
|
+
|
|
2211
|
+
Each transition is one-way: once on cloud, the panel does not surface a revert-to-local button. Disconnecting from the cloud temporarily is a follow-up; for v1.13 the in-place reconnection happens automatically when the GUI reopens.
|
|
2212
|
+
|
|
2213
|
+
Public API surface (the GUI's `/api/dbconfig/*` routes are thin wrappers):
|
|
2214
|
+
|
|
2215
|
+
```ts
|
|
2216
|
+
import {
|
|
2217
|
+
Lattice,
|
|
2218
|
+
migrateLatticeData,
|
|
2219
|
+
archiveLocalSqlite,
|
|
2220
|
+
openTargetLatticeForMigration,
|
|
2221
|
+
probeCloud,
|
|
2222
|
+
TeamsClient,
|
|
2223
|
+
} from 'latticesql';
|
|
2224
|
+
|
|
2225
|
+
// 1. Migrate a local SQLite project to a fresh cloud Postgres
|
|
2226
|
+
const source = new Lattice({ config: './lattice.config.yml' }, { encryptionKey });
|
|
2227
|
+
await source.init();
|
|
2228
|
+
const target = await openTargetLatticeForMigration('./lattice.config.yml', cloudUrl, encryptionKey);
|
|
2229
|
+
const result = await migrateLatticeData(source, target);
|
|
2230
|
+
// → { tablesCopied: ['files','items','secrets',...], rowsCopied: 42 }
|
|
2231
|
+
target.close();
|
|
2232
|
+
archiveLocalSqlite('./data/project.db'); // renames to .db.local-bak
|
|
2233
|
+
|
|
2234
|
+
// 2. Probe an arbitrary cloud URL for reachability + team status
|
|
2235
|
+
const probe = await probeCloud('postgres://u:p@host/db');
|
|
2236
|
+
// → { reachable: true, dialect: 'postgres', teamEnabled: false }
|
|
2237
|
+
|
|
2238
|
+
// 3. Connect a fresh project to an existing cloud (auto-redeems if it's a teams DB)
|
|
2239
|
+
const client = new TeamsClient(source);
|
|
2240
|
+
await client.connectToExistingCloud({
|
|
2241
|
+
label: 'atlas',
|
|
2242
|
+
cloudUrl: 'postgres://u:p@host/db',
|
|
2243
|
+
invite_token: 'latinv_...',
|
|
2244
|
+
email: 'bob@example.com',
|
|
2245
|
+
name: 'Bob',
|
|
2246
|
+
});
|
|
2247
|
+
|
|
2248
|
+
// 4. Upgrade an already-connected cloud DB to a team cloud
|
|
2249
|
+
await client.upgradeToTeamCloud({
|
|
2250
|
+
label: 'atlas',
|
|
2251
|
+
cloudUrl: 'postgres://u:p@host/db',
|
|
2252
|
+
teamName: 'Atlas',
|
|
2253
|
+
email: 'alice@example.com',
|
|
2254
|
+
displayName: 'Alice',
|
|
2255
|
+
});
|
|
2256
|
+
```
|
|
2257
|
+
|
|
2258
|
+
GUI consumers don't need to call these directly — the Database panel surfaces them as wizards (`Migrate to cloud →`, `Connect to existing cloud →`, `Upgrade to team cloud →`).
|
|
2259
|
+
|
|
2260
|
+
HTTP surface (all under `/api/dbconfig/*`, localhost-only, same auth model as the rest of `lattice gui`):
|
|
2261
|
+
|
|
2262
|
+
| Method | Route | Wraps |
|
|
2263
|
+
| ------ | ----------------------------------------- | --------------------------------------------- |
|
|
2264
|
+
| GET | `/api/dbconfig` | returns `{ type, state, label?, host?, ... }` |
|
|
2265
|
+
| POST | `/api/dbconfig/probe` | `probeCloud(url)` |
|
|
2266
|
+
| POST | `/api/dbconfig/migrate-to-cloud` | `migrateLatticeData` + `archiveLocalSqlite` |
|
|
2267
|
+
| POST | `/api/dbconfig/connect-existing` | `TeamsClient.connectToExistingCloud` |
|
|
2268
|
+
| POST | `/api/dbconfig/upgrade-to-team` | `TeamsClient.upgradeToTeamCloud` |
|
|
2269
|
+
| POST | `/api/dbconfig/save` / `connect` / `test` | unchanged from v1.12 |
|
|
2270
|
+
|
|
2271
|
+
The `state` field on `GET /api/dbconfig` is one of: `local`, `cloud-connected`, `team-cloud-creator`, `team-cloud-member`, `team-cloud-needs-invite`. The SPA badge color-codes them; the routes use them only for response shape.
|
|
2272
|
+
|
|
2112
2273
|
---
|
|
2113
2274
|
|
|
2114
2275
|
## Schema migrations
|