latticesql 1.13.9 → 1.14.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 CHANGED
@@ -2096,7 +2096,7 @@ The convergence means you don't need to duplicate entity-context definitions in
2096
2096
  - **Dashboard** (`#/`) — one card per first-class entity with live row counts.
2097
2097
  - **Table view** (`#/objects/<entity>`) — intrinsic columns, `belongsTo` chips, and a column per junction this entity participates in.
2098
2098
  - **Detail view** (`#/objects/<entity>/<id>`) — read mode by default; `Edit` flips cells into inputs (`Save` PATCHes, `Cancel` reverts).
2099
- - **Data Model** (`#/settings/data-model`) — entity-level graph plus a side panel for adding / removing junction-table links between rows.
2099
+ - **Data Model** (inside **Database Settings**, v1.14+) — entity-level graph including the native `files`/`secrets` objects, with a per-entity editor. On a team cloud each table you own carries a **Share with team / Unshare** toggle. (Pre-1.14 this was a separate `#/settings/data-model` nav item; that hash still resolves for back-compat.)
2100
2100
 
2101
2101
  **Internal tables added on first open**
2102
2102
 
@@ -2112,18 +2112,22 @@ These tables are prefixed with `_lattice_gui_` and are hidden from `/api/entitie
2112
2112
 
2113
2113
  **HTTP surface** (all routes scoped to `http://127.0.0.1:<port>/api`):
2114
2114
 
2115
- | Route | Method | Lattice call |
2116
- | -------------------------- | ------ | ----------------------------- |
2117
- | `/project` | GET | (config + manifest summary) |
2118
- | `/entities` | GET | tables + `db.count` per table |
2119
- | `/graph` | GET | (schema graph for Data Model) |
2120
- | `/tables/:table/rows` | GET | `db.query(table, …)` |
2121
- | `/tables/:table/rows` | POST | `db.insert(table, body)` |
2122
- | `/tables/:table/rows/:id` | GET | `db.get(table, id)` |
2123
- | `/tables/:table/rows/:id` | PATCH | `db.update(table, id, body)` |
2124
- | `/tables/:table/rows/:id` | DELETE | `db.delete(table, id)` |
2125
- | `/tables/:junction/link` | POST | `db.link(junction, body)` |
2126
- | `/tables/:junction/unlink` | POST | `db.unlink(junction, body)` |
2115
+ | Route | Method | Lattice call |
2116
+ | ------------------------------ | ------ | --------------------------------------------------------------- |
2117
+ | `/project` | GET | (config + manifest summary) |
2118
+ | `/entities` | GET | tables + `db.count` per table |
2119
+ | `/graph` | GET | (schema graph for Data Model) |
2120
+ | `/tables/:table/rows` | GET | `db.query(table, …)` |
2121
+ | `/tables/:table/rows` | POST | `db.insert(table, body)` |
2122
+ | `/tables/:table/rows/:id` | GET | `db.get(table, id)` |
2123
+ | `/tables/:table/rows/:id` | PATCH | `db.update(table, id, body)` |
2124
+ | `/tables/:table/rows/:id` | DELETE | `db.delete(table, id)` |
2125
+ | `/tables/:junction/link` | POST | `db.link(junction, body)` |
2126
+ | `/tables/:junction/unlink` | POST | `db.unlink(junction, body)` |
2127
+ | `/schema/entities` | POST | create a new entity/table |
2128
+ | `/schema/entities/:name/share` | POST | share/unshare a table you own with the team (cloud, owner-only) |
2129
+
2130
+ On a team cloud, `/entities` and `/graph` (and the queryable `/tables/*` allowlist) are filtered to the tables you own plus tables shared to the team — so the API surface matches exactly what the GUI shows; a table you can't see is not reachable. `/entities` rows carry `shared` / `ownedByMe` flags in that mode.
2127
2131
 
2128
2132
  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.
2129
2133
 
@@ -2150,6 +2154,18 @@ registerNativeEntities(db);
2150
2154
  await db.init();
2151
2155
  ```
2152
2156
 
2157
+ `isNativeEntity(name)` / `NATIVE_ENTITY_NAMES` are the single source of truth for "is this table a framework-shipped native object?" — adding a key to `NATIVE_ENTITY_DEFS` flows everywhere automatically (table creation, GUI surfacing, recognition).
2158
+
2159
+ **Adopting an existing `files`/`secrets` table (v1.14+).** If a database already has its own `files` or `secrets` table — possibly with a different/legacy column shape — `adoptNativeEntities(db)` (run after `init()`) labels that physical table as THE native object instead of duplicating it: it merges the native column superset non-destructively (`CREATE TABLE IF NOT EXISTS` + `ADD COLUMN IF NOT EXISTS`, never dropping data) and records the binding in an internal `__lattice_native_entities` registry. Legacy plaintext `secrets.value` rows stay readable (decrypt passes non-`enc:` values through) and new writes encrypt. `listNativeBindings(db)` reads the bindings. The GUI runs this automatically on every open and exposes the bindings at `GET /api/native-entities`.
2160
+
2161
+ ```ts
2162
+ import { adoptNativeEntities, listNativeBindings } from 'latticesql';
2163
+
2164
+ await db.init();
2165
+ await adoptNativeEntities(db); // merge + label existing files/secrets as native
2166
+ const bindings = await listNativeBindings(db); // [{ entity, tableName, origin }]
2167
+ ```
2168
+
2153
2169
  **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:
2154
2170
 
2155
2171
  | File | Purpose |
@@ -2222,7 +2238,9 @@ The cloud rejects redemption if the caller's claimed email doesn't match the inv
2222
2238
 
2223
2239
  **Other subcommands** (`lattice teams help` for the full list): `list`, `members`, `leave`, `destroy`, `share`, `unshare`, `shared`, `sync`, `link`, `unlink`, `pull`, `push`, `status`.
2224
2240
 
2225
- **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.
2241
+ **Per-table ownership + opt-in sharing (v1.14+).** Team members share one physical Postgres, so visibility is enforced at the app layer via a `__lattice_object_owners` table: each table records its creator, and a user sees only the tables they own plus tables explicitly shared to the team. The native `files`/`secrets` objects are owned by the database creator and private by default. Sharing is an explicit, owner-only action (not a side effect of creating a table). The filter gates API access, not just the display.
2242
+
2243
+ **Same flows from the GUI (v1.14+).** The local `lattice gui` drives the entire teams lifecycle from **Database Settings**: rename (owner-only), invite by email (owner-only), the inline Members list (the owner is always shown as `creator`; your own row offers Leave/Destroy; non-owners can't kick), share/unshare from the Data Model, and sync status. Member admin is resolved from `GET /api/dbconfig` against the active cloud DB, so it works even when the team cloud itself is the active database. Identity (display name + email) comes from `~/.lattice/identity.json` and is locked in the Join modal. Leaving a team removes the local config + credential and switches you to another database.
2226
2244
 
2227
2245
  **Joining via the GUI is one click (v1.13.7+).** When you click "Join via invite" and the redeem succeeds, the team's cloud URL is automatically saved as a switchable database credential and a sibling YAML config is written to your project directory. The new entry shows up in the database dropdown as `<team-name>.config`. Clicking it opens the SPA with the team's shared tables already populated — no YAML editing, no `db.define()` calls.
2228
2246