latticesql 3.4.3 → 3.4.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/dist/index.d.cts CHANGED
@@ -24,10 +24,50 @@ interface EntityContextManifestEntry {
24
24
  */
25
25
  entities: Record<string, Record<string, EntityFileManifestInfo> | string[]>;
26
26
  }
27
+ /**
28
+ * Monotonic cursor the rendered tree was produced FROM, recorded in the manifest
29
+ * so a later open can decide whether anything the tree depends on has advanced.
30
+ *
31
+ * Each field is a string-comparable high-water mark (or `null` when the substrate
32
+ * is absent / unreadable in the current scope). Computed THROUGH the same DB
33
+ * connection + read scope the render used, so for a cloud MEMBER each mark
34
+ * reflects only what that member can see — making the cursor a per-viewer
35
+ * freshness key, not a global one.
36
+ *
37
+ * - `changelog` — the write log's high-water mark. Captures plain data edits AND
38
+ * the per-viewer DERIVED observations a member's tree folds in (both are
39
+ * changelog rows), so a new observation advances it even though no entity row's
40
+ * count moved.
41
+ * - `grants` / `owners` — the row-sharing graph's high-water mark. A share or
42
+ * un-share changes a member's visible row set without touching any entity row,
43
+ * so these capture that class of change. For a member they are derived from the
44
+ * member-visible change feed (the only share signal a member may read); for an
45
+ * owner / local DB they come from the ownership + grant bookkeeping directly.
46
+ */
47
+ interface RenderCursor {
48
+ changelog: string | null;
49
+ grants: string | null;
50
+ owners: string | null;
51
+ }
27
52
  interface LatticeManifest {
28
53
  version: 1 | 2;
29
54
  generated_at: string;
30
55
  entityContexts: Record<string, EntityContextManifestEntry>;
56
+ /**
57
+ * Render-output format version the tree was produced with (see
58
+ * {@link TEMPLATE_VERSION}). Optional: a manifest written before this field
59
+ * existed reads as `undefined`, which the staleness gate treats as a mismatch
60
+ * → full render (fail-open). Set on every render that writes a manifest.
61
+ */
62
+ templateVersion?: number;
63
+ /**
64
+ * The cursor the tree was rendered from (see {@link RenderCursor}). Optional for
65
+ * the same backward-compat reason; absence → the gate fails open and renders.
66
+ * On an INCREMENTAL render this is recomputed from the live DB (a single
67
+ * top-level cursor reflecting the latest computation), NOT merged per-table — so
68
+ * it always advances to the newest state the partial render observed.
69
+ */
70
+ cursor?: RenderCursor;
31
71
  }
32
72
  /** Type guard: is the entity files entry in v1 format (string[])? */
33
73
  declare function isV1EntityFiles(val: unknown): val is string[];
@@ -1826,6 +1866,18 @@ interface RenderOptions {
1826
1866
  * Omitted → a full render of everything (initial open, explicit `render()`).
1827
1867
  */
1828
1868
  changedTables?: ReadonlySet<string>;
1869
+ /**
1870
+ * Open/restart staleness gate. When set, the render first compares the manifest's
1871
+ * recorded template version + cursor to the live state (through the render's own
1872
+ * scope); if nothing the tree depends on has advanced, it SKIPS the render
1873
+ * entirely — reads no tables, emits no per-table progress, and fires a single
1874
+ * terminal `done` so the GUI shows complete. Used ONLY by the GUI's open-time
1875
+ * background render so a plain restart / version bump doesn't re-render an
1876
+ * unchanged tree. The realtime eager-render and the mutation auto-render never
1877
+ * set it (they must always re-render the table that actually changed). Fails
1878
+ * OPEN: any uncertainty (missing/foreign manifest, unreadable cursor) renders.
1879
+ */
1880
+ gateOnOpen?: boolean;
1829
1881
  }
1830
1882
  /**
1831
1883
  * Coalesces high-frequency `table-progress` events down to ≤ ~5/sec per table,
@@ -1937,6 +1989,14 @@ declare class Lattice {
1937
1989
  private readonly _changelogTables;
1938
1990
  /** Current task context string for relevance filtering. */
1939
1991
  private _taskContext;
1992
+ /**
1993
+ * True when this connection opened against an already-provisioned cloud as a
1994
+ * SCOPED MEMBER (no role-management privilege → no CREATE/ALTER on the schema).
1995
+ * Set during init() by the same probe that decides introspect-only. Drives
1996
+ * {@link addColumn} to route DDL through the owner-side `lattice_member_add_column`
1997
+ * SECURITY DEFINER helper instead of issuing a raw ALTER the member can't run.
1998
+ */
1999
+ private _cloudMemberOpen;
1940
2000
  private readonly _auditHandlers;
1941
2001
  private readonly _renderHandlers;
1942
2002
  private readonly _writebackHandlers;
@@ -2048,6 +2108,22 @@ declare class Lattice {
2048
2108
  * Teams schema spec → DDL translation).
2049
2109
  */
2050
2110
  getDialect(): 'sqlite' | 'postgres';
2111
+ /**
2112
+ * True when a table opts into the observation/changelog substrate
2113
+ * (`def.changelog`). Callers that want to bypass the high-level {@link delete}
2114
+ * with a transaction-scoped raw delete use this to know whether the table also
2115
+ * needs the changelog / write-hook / embedding side effects that only
2116
+ * `delete()` performs — so they can keep the high-level path for such tables.
2117
+ */
2118
+ isChangelogTracked(table: string): boolean;
2119
+ /**
2120
+ * True when this connection opened as a scoped cloud MEMBER (see
2121
+ * {@link _cloudMemberOpen}). Callers use it to route DDL-bearing work through
2122
+ * the owner-side SECURITY DEFINER helpers rather than issuing DDL the member's
2123
+ * role can't run (e.g. {@link addColumn} regenerates the masking view inside
2124
+ * `lattice_member_add_column`, so the caller must not also try to regenerate it).
2125
+ */
2126
+ isCloudMemberOpen(): boolean;
2051
2127
  /**
2052
2128
  * Return the normalised primary-key column list for a registered
2053
2129
  * table. Falls back to `['id']` for tables registered via raw DDL
@@ -4847,6 +4923,37 @@ interface PdfOptions {
4847
4923
  */
4848
4924
  declare function describePdf(auth: ClaudeAuth, path: string, opts?: PdfOptions): Promise<string>;
4849
4925
 
4926
+ /** How the running copy of the package was installed. */
4927
+ type InstallKind = 'global' | 'local' | 'npx' | 'linked-dev' | 'unknown';
4928
+ interface InstallContext {
4929
+ kind: InstallKind;
4930
+ /** True only when an `npm install` may safely upgrade this copy in place. */
4931
+ installable: boolean;
4932
+ /** Directory to run the install from (the consumer project root for `local`). */
4933
+ cwd: string;
4934
+ /** Resolved package root of the running copy, if found. */
4935
+ packageRoot: string | null;
4936
+ /** Human-readable explanation (logged / surfaced in `/api/update/status`). */
4937
+ reason: string;
4938
+ }
4939
+
4940
+ interface UpdateStatus {
4941
+ current: string;
4942
+ latest: string | null;
4943
+ kind: InstallContext['kind'];
4944
+ installable: boolean;
4945
+ checking: boolean;
4946
+ installing: boolean;
4947
+ lastError: string | null;
4948
+ }
4949
+ interface UpdateService {
4950
+ start(): void;
4951
+ stop(): void;
4952
+ status(): UpdateStatus;
4953
+ /** Run a check now (and install if applicable). Returns the resulting status. */
4954
+ checkNow(force?: boolean): Promise<UpdateStatus>;
4955
+ }
4956
+
4850
4957
  interface StartGuiServerOptions {
4851
4958
  /**
4852
4959
  * Active workspace config to open. NULL/empty ⇒ boot into the zero-workspace
@@ -4903,6 +5010,13 @@ interface StartGuiServerOptions {
4903
5010
  * `GET /api/version` + `GET /api/update/status` are served regardless.
4904
5011
  */
4905
5012
  selfUpdate?: boolean;
5013
+ /**
5014
+ * Test seam: supply the update service instead of building one from the real
5015
+ * npm-backed install context. Lets tests exercise the update routes against a
5016
+ * deterministic fake (no real registry check, no real npm install). When set,
5017
+ * it overrides `selfUpdate`'s default factory.
5018
+ */
5019
+ updateServiceFactory?: (emit: (type: string, data: unknown) => void) => UpdateService;
4906
5020
  }
4907
5021
  interface GuiServerHandle {
4908
5022
  server: Server;
package/dist/index.d.ts CHANGED
@@ -24,10 +24,50 @@ interface EntityContextManifestEntry {
24
24
  */
25
25
  entities: Record<string, Record<string, EntityFileManifestInfo> | string[]>;
26
26
  }
27
+ /**
28
+ * Monotonic cursor the rendered tree was produced FROM, recorded in the manifest
29
+ * so a later open can decide whether anything the tree depends on has advanced.
30
+ *
31
+ * Each field is a string-comparable high-water mark (or `null` when the substrate
32
+ * is absent / unreadable in the current scope). Computed THROUGH the same DB
33
+ * connection + read scope the render used, so for a cloud MEMBER each mark
34
+ * reflects only what that member can see — making the cursor a per-viewer
35
+ * freshness key, not a global one.
36
+ *
37
+ * - `changelog` — the write log's high-water mark. Captures plain data edits AND
38
+ * the per-viewer DERIVED observations a member's tree folds in (both are
39
+ * changelog rows), so a new observation advances it even though no entity row's
40
+ * count moved.
41
+ * - `grants` / `owners` — the row-sharing graph's high-water mark. A share or
42
+ * un-share changes a member's visible row set without touching any entity row,
43
+ * so these capture that class of change. For a member they are derived from the
44
+ * member-visible change feed (the only share signal a member may read); for an
45
+ * owner / local DB they come from the ownership + grant bookkeeping directly.
46
+ */
47
+ interface RenderCursor {
48
+ changelog: string | null;
49
+ grants: string | null;
50
+ owners: string | null;
51
+ }
27
52
  interface LatticeManifest {
28
53
  version: 1 | 2;
29
54
  generated_at: string;
30
55
  entityContexts: Record<string, EntityContextManifestEntry>;
56
+ /**
57
+ * Render-output format version the tree was produced with (see
58
+ * {@link TEMPLATE_VERSION}). Optional: a manifest written before this field
59
+ * existed reads as `undefined`, which the staleness gate treats as a mismatch
60
+ * → full render (fail-open). Set on every render that writes a manifest.
61
+ */
62
+ templateVersion?: number;
63
+ /**
64
+ * The cursor the tree was rendered from (see {@link RenderCursor}). Optional for
65
+ * the same backward-compat reason; absence → the gate fails open and renders.
66
+ * On an INCREMENTAL render this is recomputed from the live DB (a single
67
+ * top-level cursor reflecting the latest computation), NOT merged per-table — so
68
+ * it always advances to the newest state the partial render observed.
69
+ */
70
+ cursor?: RenderCursor;
31
71
  }
32
72
  /** Type guard: is the entity files entry in v1 format (string[])? */
33
73
  declare function isV1EntityFiles(val: unknown): val is string[];
@@ -1826,6 +1866,18 @@ interface RenderOptions {
1826
1866
  * Omitted → a full render of everything (initial open, explicit `render()`).
1827
1867
  */
1828
1868
  changedTables?: ReadonlySet<string>;
1869
+ /**
1870
+ * Open/restart staleness gate. When set, the render first compares the manifest's
1871
+ * recorded template version + cursor to the live state (through the render's own
1872
+ * scope); if nothing the tree depends on has advanced, it SKIPS the render
1873
+ * entirely — reads no tables, emits no per-table progress, and fires a single
1874
+ * terminal `done` so the GUI shows complete. Used ONLY by the GUI's open-time
1875
+ * background render so a plain restart / version bump doesn't re-render an
1876
+ * unchanged tree. The realtime eager-render and the mutation auto-render never
1877
+ * set it (they must always re-render the table that actually changed). Fails
1878
+ * OPEN: any uncertainty (missing/foreign manifest, unreadable cursor) renders.
1879
+ */
1880
+ gateOnOpen?: boolean;
1829
1881
  }
1830
1882
  /**
1831
1883
  * Coalesces high-frequency `table-progress` events down to ≤ ~5/sec per table,
@@ -1937,6 +1989,14 @@ declare class Lattice {
1937
1989
  private readonly _changelogTables;
1938
1990
  /** Current task context string for relevance filtering. */
1939
1991
  private _taskContext;
1992
+ /**
1993
+ * True when this connection opened against an already-provisioned cloud as a
1994
+ * SCOPED MEMBER (no role-management privilege → no CREATE/ALTER on the schema).
1995
+ * Set during init() by the same probe that decides introspect-only. Drives
1996
+ * {@link addColumn} to route DDL through the owner-side `lattice_member_add_column`
1997
+ * SECURITY DEFINER helper instead of issuing a raw ALTER the member can't run.
1998
+ */
1999
+ private _cloudMemberOpen;
1940
2000
  private readonly _auditHandlers;
1941
2001
  private readonly _renderHandlers;
1942
2002
  private readonly _writebackHandlers;
@@ -2048,6 +2108,22 @@ declare class Lattice {
2048
2108
  * Teams schema spec → DDL translation).
2049
2109
  */
2050
2110
  getDialect(): 'sqlite' | 'postgres';
2111
+ /**
2112
+ * True when a table opts into the observation/changelog substrate
2113
+ * (`def.changelog`). Callers that want to bypass the high-level {@link delete}
2114
+ * with a transaction-scoped raw delete use this to know whether the table also
2115
+ * needs the changelog / write-hook / embedding side effects that only
2116
+ * `delete()` performs — so they can keep the high-level path for such tables.
2117
+ */
2118
+ isChangelogTracked(table: string): boolean;
2119
+ /**
2120
+ * True when this connection opened as a scoped cloud MEMBER (see
2121
+ * {@link _cloudMemberOpen}). Callers use it to route DDL-bearing work through
2122
+ * the owner-side SECURITY DEFINER helpers rather than issuing DDL the member's
2123
+ * role can't run (e.g. {@link addColumn} regenerates the masking view inside
2124
+ * `lattice_member_add_column`, so the caller must not also try to regenerate it).
2125
+ */
2126
+ isCloudMemberOpen(): boolean;
2051
2127
  /**
2052
2128
  * Return the normalised primary-key column list for a registered
2053
2129
  * table. Falls back to `['id']` for tables registered via raw DDL
@@ -4847,6 +4923,37 @@ interface PdfOptions {
4847
4923
  */
4848
4924
  declare function describePdf(auth: ClaudeAuth, path: string, opts?: PdfOptions): Promise<string>;
4849
4925
 
4926
+ /** How the running copy of the package was installed. */
4927
+ type InstallKind = 'global' | 'local' | 'npx' | 'linked-dev' | 'unknown';
4928
+ interface InstallContext {
4929
+ kind: InstallKind;
4930
+ /** True only when an `npm install` may safely upgrade this copy in place. */
4931
+ installable: boolean;
4932
+ /** Directory to run the install from (the consumer project root for `local`). */
4933
+ cwd: string;
4934
+ /** Resolved package root of the running copy, if found. */
4935
+ packageRoot: string | null;
4936
+ /** Human-readable explanation (logged / surfaced in `/api/update/status`). */
4937
+ reason: string;
4938
+ }
4939
+
4940
+ interface UpdateStatus {
4941
+ current: string;
4942
+ latest: string | null;
4943
+ kind: InstallContext['kind'];
4944
+ installable: boolean;
4945
+ checking: boolean;
4946
+ installing: boolean;
4947
+ lastError: string | null;
4948
+ }
4949
+ interface UpdateService {
4950
+ start(): void;
4951
+ stop(): void;
4952
+ status(): UpdateStatus;
4953
+ /** Run a check now (and install if applicable). Returns the resulting status. */
4954
+ checkNow(force?: boolean): Promise<UpdateStatus>;
4955
+ }
4956
+
4850
4957
  interface StartGuiServerOptions {
4851
4958
  /**
4852
4959
  * Active workspace config to open. NULL/empty ⇒ boot into the zero-workspace
@@ -4903,6 +5010,13 @@ interface StartGuiServerOptions {
4903
5010
  * `GET /api/version` + `GET /api/update/status` are served regardless.
4904
5011
  */
4905
5012
  selfUpdate?: boolean;
5013
+ /**
5014
+ * Test seam: supply the update service instead of building one from the real
5015
+ * npm-backed install context. Lets tests exercise the update routes against a
5016
+ * deterministic fake (no real registry check, no real npm install). When set,
5017
+ * it overrides `selfUpdate`'s default factory.
5018
+ */
5019
+ updateServiceFactory?: (emit: (type: string, data: unknown) => void) => UpdateService;
4906
5020
  }
4907
5021
  interface GuiServerHandle {
4908
5022
  server: Server;