latticesql 3.3.3 → 3.3.4

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/cli.js CHANGED
@@ -1061,13 +1061,24 @@ function moduleContext() {
1061
1061
  return _moduleContext;
1062
1062
  }
1063
1063
  async function registerPostgresPolyfills(run) {
1064
+ let permissionDenied = false;
1064
1065
  for (const { warn, sql } of POSTGRES_POLYFILLS) {
1065
1066
  try {
1066
1067
  await run(sql);
1067
1068
  } catch (err) {
1068
- console.warn(`[PostgresAdapter] ${warn}`, err instanceof Error ? err.message : err);
1069
+ const msg = err instanceof Error ? err.message : String(err);
1070
+ if (/permission denied/i.test(msg)) {
1071
+ permissionDenied = true;
1072
+ } else {
1073
+ console.warn(`[PostgresAdapter] ${warn}`, msg);
1074
+ }
1069
1075
  }
1070
1076
  }
1077
+ if (permissionDenied) {
1078
+ console.debug(
1079
+ "[PostgresAdapter] SQLite-compat polyfills are owner-managed on this cloud; skipping member-side (re)creation (expected)."
1080
+ );
1081
+ }
1071
1082
  }
1072
1083
  function translateDialect(sql) {
1073
1084
  if (/INSERT\s+OR\s+REPLACE\s+INTO/i.test(sql)) {
@@ -5103,7 +5114,23 @@ var init_lattice = __esm({
5103
5114
  }
5104
5115
  /** Async tail of init(). See {@link init} for the sync-validation phase. */
5105
5116
  async _initAsync(options) {
5106
- if (options.introspectOnly) {
5117
+ let introspectOnly = options.introspectOnly === true;
5118
+ if (!introspectOnly && this.getDialect() === "postgres") {
5119
+ try {
5120
+ const [marker, role] = await Promise.all([
5121
+ getAsyncOrSync(this._adapter, `SELECT to_regclass('__lattice_owners') AS reg`),
5122
+ getAsyncOrSync(
5123
+ this._adapter,
5124
+ `SELECT rolcreaterole FROM pg_roles WHERE rolname = current_user`
5125
+ )
5126
+ ]);
5127
+ const provisioned = !!marker && marker.reg != null;
5128
+ const canCreateRoles = !!role && role.rolcreaterole === true;
5129
+ introspectOnly = provisioned && !canCreateRoles;
5130
+ } catch {
5131
+ }
5132
+ }
5133
+ if (introspectOnly) {
5107
5134
  for (const tableName of this._schema.getTables().keys()) {
5108
5135
  try {
5109
5136
  const cols = await introspectColumnsAsyncOrSync(this._adapter, tableName);
@@ -57051,7 +57078,7 @@ var appJs = `
57051
57078
  '<div class="view-header">' +
57052
57079
  '<span class="entity-icon">\u2699</span>' +
57053
57080
  '<h1>' + escapeHtml(tableName) + '</h1>' +
57054
- '<span class="count">' + entry.rowCount + ' row' + (entry.rowCount === 1 ? '' : 's') +
57081
+ '<span class="count">' + (entry.rowCount == null ? 'no access' : (entry.rowCount + ' row' + (entry.rowCount === 1 ? '' : 's'))) +
57055
57082
  ' \xB7 read-only</span>' +
57056
57083
  '</div>' +
57057
57084
  '<div class="muted" style="margin-bottom:12px;font-size:13px;">' +
@@ -61804,6 +61831,14 @@ async function reconcileCloudMemberAccess(db) {
61804
61831
  );
61805
61832
  }
61806
61833
  }
61834
+ await runAsyncOrSync(
61835
+ db.adapter,
61836
+ `DO $LATTICE$ BEGIN
61837
+ IF to_regclass('__lattice_changelog') IS NOT NULL THEN
61838
+ EXECUTE 'GRANT SELECT, INSERT ON "__lattice_changelog" TO ${MEMBER_GROUP}';
61839
+ END IF;
61840
+ END $LATTICE$`
61841
+ );
61807
61842
  }
61808
61843
  async function secureNewCloudTable(db, table, pk) {
61809
61844
  if (db.getDialect() !== "postgres") return;
@@ -65337,6 +65372,7 @@ async function openConfig(configPath, outputDir, autoRender = false, realtimeWat
65337
65372
  ]);
65338
65373
  const views = viewsRaw;
65339
65374
  const knownTables = /* @__PURE__ */ new Set([...declared, ...discovered.map((t8) => t8.name)]);
65375
+ const memberEntityDefs = [];
65340
65376
  for (const t8 of discovered) {
65341
65377
  if (declared.has(t8.name)) continue;
65342
65378
  if (t8.columns.length === 0) continue;
@@ -65344,17 +65380,25 @@ async function openConfig(configPath, outputDir, autoRender = false, realtimeWat
65344
65380
  discoveredJunctions.add(t8.name);
65345
65381
  continue;
65346
65382
  }
65347
- db.define(t8.name, {
65383
+ const def = {
65348
65384
  columns: Object.fromEntries(t8.columns.map((c6) => [c6, "TEXT"])),
65349
65385
  ...t8.pk.length > 0 ? { primaryKey: t8.pk.length === 1 ? t8.pk[0] : t8.pk } : {},
65350
65386
  render: () => "",
65351
65387
  outputFile: `${t8.name}/.lattice/${t8.name}.md`
65352
- });
65388
+ };
65389
+ db.define(t8.name, def);
65390
+ memberEntityDefs.push({ name: t8.name, definition: def });
65353
65391
  }
65354
65392
  for (const { name } of views) {
65355
65393
  const base = name.slice(0, -2);
65356
65394
  if (knownTables.has(base)) maskedReadViews.set(base, name);
65357
65395
  }
65396
+ if (autoRender && memberEntityDefs.length > 0) {
65397
+ const existingContexts = db.entityContexts();
65398
+ for (const { table, definition } of deriveCanonicalContexts(memberEntityDefs)) {
65399
+ if (!existingContexts.has(table)) db.defineEntityContext(table, definition);
65400
+ }
65401
+ }
65358
65402
  }
65359
65403
  }
65360
65404
  } catch {
@@ -66845,9 +66889,18 @@ async function startGuiServer(options) {
66845
66889
  }
66846
66890
  const tables = [];
66847
66891
  for (const r6 of rows) {
66848
- const cols = await active.db.introspectColumns(r6.name);
66849
- const rowCount = await active.db.count(r6.name);
66850
- tables.push({ name: r6.name, columns: cols, rowCount });
66892
+ try {
66893
+ const cols = await active.db.introspectColumns(r6.name);
66894
+ const rowCount = await active.db.count(r6.name);
66895
+ tables.push({ name: r6.name, columns: cols, rowCount });
66896
+ } catch (err) {
66897
+ const msg = err instanceof Error ? err.message : String(err);
66898
+ if (/permission denied|does not exist/i.test(msg)) {
66899
+ tables.push({ name: r6.name, columns: [], rowCount: null });
66900
+ } else {
66901
+ throw err;
66902
+ }
66903
+ }
66851
66904
  }
66852
66905
  sendJson(res, { tables });
66853
66906
  return;
@@ -67813,7 +67866,7 @@ function printHelp() {
67813
67866
  );
67814
67867
  }
67815
67868
  function getVersion() {
67816
- if (true) return "3.3.3";
67869
+ if (true) return "3.3.4";
67817
67870
  try {
67818
67871
  const pkgPath = new URL("../package.json", import.meta.url).pathname;
67819
67872
  const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
package/dist/index.cjs CHANGED
@@ -437,13 +437,24 @@ function moduleContext() {
437
437
  return _moduleContext;
438
438
  }
439
439
  async function registerPostgresPolyfills(run) {
440
+ let permissionDenied = false;
440
441
  for (const { warn, sql } of POSTGRES_POLYFILLS) {
441
442
  try {
442
443
  await run(sql);
443
444
  } catch (err) {
444
- console.warn(`[PostgresAdapter] ${warn}`, err instanceof Error ? err.message : err);
445
+ const msg = err instanceof Error ? err.message : String(err);
446
+ if (/permission denied/i.test(msg)) {
447
+ permissionDenied = true;
448
+ } else {
449
+ console.warn(`[PostgresAdapter] ${warn}`, msg);
450
+ }
445
451
  }
446
452
  }
453
+ if (permissionDenied) {
454
+ console.debug(
455
+ "[PostgresAdapter] SQLite-compat polyfills are owner-managed on this cloud; skipping member-side (re)creation (expected)."
456
+ );
457
+ }
447
458
  }
448
459
  function translateDialect(sql) {
449
460
  if (/INSERT\s+OR\s+REPLACE\s+INTO/i.test(sql)) {
@@ -5266,7 +5277,23 @@ var init_lattice = __esm({
5266
5277
  }
5267
5278
  /** Async tail of init(). See {@link init} for the sync-validation phase. */
5268
5279
  async _initAsync(options) {
5269
- if (options.introspectOnly) {
5280
+ let introspectOnly = options.introspectOnly === true;
5281
+ if (!introspectOnly && this.getDialect() === "postgres") {
5282
+ try {
5283
+ const [marker, role] = await Promise.all([
5284
+ getAsyncOrSync(this._adapter, `SELECT to_regclass('__lattice_owners') AS reg`),
5285
+ getAsyncOrSync(
5286
+ this._adapter,
5287
+ `SELECT rolcreaterole FROM pg_roles WHERE rolname = current_user`
5288
+ )
5289
+ ]);
5290
+ const provisioned = !!marker && marker.reg != null;
5291
+ const canCreateRoles = !!role && role.rolcreaterole === true;
5292
+ introspectOnly = provisioned && !canCreateRoles;
5293
+ } catch {
5294
+ }
5295
+ }
5296
+ if (introspectOnly) {
5270
5297
  for (const tableName of this._schema.getTables().keys()) {
5271
5298
  try {
5272
5299
  const cols = await introspectColumnsAsyncOrSync(this._adapter, tableName);
@@ -54054,6 +54081,14 @@ async function reconcileCloudMemberAccess(db) {
54054
54081
  );
54055
54082
  }
54056
54083
  }
54084
+ await runAsyncOrSync(
54085
+ db.adapter,
54086
+ `DO $LATTICE$ BEGIN
54087
+ IF to_regclass('__lattice_changelog') IS NOT NULL THEN
54088
+ EXECUTE 'GRANT SELECT, INSERT ON "__lattice_changelog" TO ${MEMBER_GROUP}';
54089
+ END IF;
54090
+ END $LATTICE$`
54091
+ );
54057
54092
  }
54058
54093
  async function secureNewCloudTable(db, table, pk) {
54059
54094
  if (db.getDialect() !== "postgres") return;
@@ -58951,7 +58986,7 @@ var appJs = `
58951
58986
  '<div class="view-header">' +
58952
58987
  '<span class="entity-icon">\u2699</span>' +
58953
58988
  '<h1>' + escapeHtml(tableName) + '</h1>' +
58954
- '<span class="count">' + entry.rowCount + ' row' + (entry.rowCount === 1 ? '' : 's') +
58989
+ '<span class="count">' + (entry.rowCount == null ? 'no access' : (entry.rowCount + ' row' + (entry.rowCount === 1 ? '' : 's'))) +
58955
58990
  ' \xB7 read-only</span>' +
58956
58991
  '</div>' +
58957
58992
  '<div class="muted" style="margin-bottom:12px;font-size:13px;">' +
@@ -66509,6 +66544,7 @@ async function openConfig(configPath, outputDir, autoRender = false, realtimeWat
66509
66544
  ]);
66510
66545
  const views = viewsRaw;
66511
66546
  const knownTables = /* @__PURE__ */ new Set([...declared, ...discovered.map((t8) => t8.name)]);
66547
+ const memberEntityDefs = [];
66512
66548
  for (const t8 of discovered) {
66513
66549
  if (declared.has(t8.name)) continue;
66514
66550
  if (t8.columns.length === 0) continue;
@@ -66516,17 +66552,25 @@ async function openConfig(configPath, outputDir, autoRender = false, realtimeWat
66516
66552
  discoveredJunctions.add(t8.name);
66517
66553
  continue;
66518
66554
  }
66519
- db.define(t8.name, {
66555
+ const def = {
66520
66556
  columns: Object.fromEntries(t8.columns.map((c6) => [c6, "TEXT"])),
66521
66557
  ...t8.pk.length > 0 ? { primaryKey: t8.pk.length === 1 ? t8.pk[0] : t8.pk } : {},
66522
66558
  render: () => "",
66523
66559
  outputFile: `${t8.name}/.lattice/${t8.name}.md`
66524
- });
66560
+ };
66561
+ db.define(t8.name, def);
66562
+ memberEntityDefs.push({ name: t8.name, definition: def });
66525
66563
  }
66526
66564
  for (const { name } of views) {
66527
66565
  const base = name.slice(0, -2);
66528
66566
  if (knownTables.has(base)) maskedReadViews.set(base, name);
66529
66567
  }
66568
+ if (autoRender && memberEntityDefs.length > 0) {
66569
+ const existingContexts = db.entityContexts();
66570
+ for (const { table, definition } of deriveCanonicalContexts(memberEntityDefs)) {
66571
+ if (!existingContexts.has(table)) db.defineEntityContext(table, definition);
66572
+ }
66573
+ }
66530
66574
  }
66531
66575
  }
66532
66576
  } catch {
@@ -68017,9 +68061,18 @@ async function startGuiServer(options) {
68017
68061
  }
68018
68062
  const tables = [];
68019
68063
  for (const r6 of rows) {
68020
- const cols = await active.db.introspectColumns(r6.name);
68021
- const rowCount = await active.db.count(r6.name);
68022
- tables.push({ name: r6.name, columns: cols, rowCount });
68064
+ try {
68065
+ const cols = await active.db.introspectColumns(r6.name);
68066
+ const rowCount = await active.db.count(r6.name);
68067
+ tables.push({ name: r6.name, columns: cols, rowCount });
68068
+ } catch (err) {
68069
+ const msg = err instanceof Error ? err.message : String(err);
68070
+ if (/permission denied|does not exist/i.test(msg)) {
68071
+ tables.push({ name: r6.name, columns: [], rowCount: null });
68072
+ } else {
68073
+ throw err;
68074
+ }
68075
+ }
68023
68076
  }
68024
68077
  sendJson(res, { tables });
68025
68078
  return;
package/dist/index.js CHANGED
@@ -430,13 +430,24 @@ function moduleContext() {
430
430
  return _moduleContext;
431
431
  }
432
432
  async function registerPostgresPolyfills(run) {
433
+ let permissionDenied = false;
433
434
  for (const { warn, sql } of POSTGRES_POLYFILLS) {
434
435
  try {
435
436
  await run(sql);
436
437
  } catch (err) {
437
- console.warn(`[PostgresAdapter] ${warn}`, err instanceof Error ? err.message : err);
438
+ const msg = err instanceof Error ? err.message : String(err);
439
+ if (/permission denied/i.test(msg)) {
440
+ permissionDenied = true;
441
+ } else {
442
+ console.warn(`[PostgresAdapter] ${warn}`, msg);
443
+ }
438
444
  }
439
445
  }
446
+ if (permissionDenied) {
447
+ console.debug(
448
+ "[PostgresAdapter] SQLite-compat polyfills are owner-managed on this cloud; skipping member-side (re)creation (expected)."
449
+ );
450
+ }
440
451
  }
441
452
  function translateDialect(sql) {
442
453
  if (/INSERT\s+OR\s+REPLACE\s+INTO/i.test(sql)) {
@@ -5262,7 +5273,23 @@ var init_lattice = __esm({
5262
5273
  }
5263
5274
  /** Async tail of init(). See {@link init} for the sync-validation phase. */
5264
5275
  async _initAsync(options) {
5265
- if (options.introspectOnly) {
5276
+ let introspectOnly = options.introspectOnly === true;
5277
+ if (!introspectOnly && this.getDialect() === "postgres") {
5278
+ try {
5279
+ const [marker, role] = await Promise.all([
5280
+ getAsyncOrSync(this._adapter, `SELECT to_regclass('__lattice_owners') AS reg`),
5281
+ getAsyncOrSync(
5282
+ this._adapter,
5283
+ `SELECT rolcreaterole FROM pg_roles WHERE rolname = current_user`
5284
+ )
5285
+ ]);
5286
+ const provisioned = !!marker && marker.reg != null;
5287
+ const canCreateRoles = !!role && role.rolcreaterole === true;
5288
+ introspectOnly = provisioned && !canCreateRoles;
5289
+ } catch {
5290
+ }
5291
+ }
5292
+ if (introspectOnly) {
5266
5293
  for (const tableName of this._schema.getTables().keys()) {
5267
5294
  try {
5268
5295
  const cols = await introspectColumnsAsyncOrSync(this._adapter, tableName);
@@ -53867,6 +53894,14 @@ async function reconcileCloudMemberAccess(db) {
53867
53894
  );
53868
53895
  }
53869
53896
  }
53897
+ await runAsyncOrSync(
53898
+ db.adapter,
53899
+ `DO $LATTICE$ BEGIN
53900
+ IF to_regclass('__lattice_changelog') IS NOT NULL THEN
53901
+ EXECUTE 'GRANT SELECT, INSERT ON "__lattice_changelog" TO ${MEMBER_GROUP}';
53902
+ END IF;
53903
+ END $LATTICE$`
53904
+ );
53870
53905
  }
53871
53906
  async function secureNewCloudTable(db, table, pk) {
53872
53907
  if (db.getDialect() !== "postgres") return;
@@ -58771,7 +58806,7 @@ var appJs = `
58771
58806
  '<div class="view-header">' +
58772
58807
  '<span class="entity-icon">\u2699</span>' +
58773
58808
  '<h1>' + escapeHtml(tableName) + '</h1>' +
58774
- '<span class="count">' + entry.rowCount + ' row' + (entry.rowCount === 1 ? '' : 's') +
58809
+ '<span class="count">' + (entry.rowCount == null ? 'no access' : (entry.rowCount + ' row' + (entry.rowCount === 1 ? '' : 's'))) +
58775
58810
  ' \xB7 read-only</span>' +
58776
58811
  '</div>' +
58777
58812
  '<div class="muted" style="margin-bottom:12px;font-size:13px;">' +
@@ -66328,6 +66363,7 @@ async function openConfig(configPath, outputDir, autoRender = false, realtimeWat
66328
66363
  ]);
66329
66364
  const views = viewsRaw;
66330
66365
  const knownTables = /* @__PURE__ */ new Set([...declared, ...discovered.map((t8) => t8.name)]);
66366
+ const memberEntityDefs = [];
66331
66367
  for (const t8 of discovered) {
66332
66368
  if (declared.has(t8.name)) continue;
66333
66369
  if (t8.columns.length === 0) continue;
@@ -66335,17 +66371,25 @@ async function openConfig(configPath, outputDir, autoRender = false, realtimeWat
66335
66371
  discoveredJunctions.add(t8.name);
66336
66372
  continue;
66337
66373
  }
66338
- db.define(t8.name, {
66374
+ const def = {
66339
66375
  columns: Object.fromEntries(t8.columns.map((c6) => [c6, "TEXT"])),
66340
66376
  ...t8.pk.length > 0 ? { primaryKey: t8.pk.length === 1 ? t8.pk[0] : t8.pk } : {},
66341
66377
  render: () => "",
66342
66378
  outputFile: `${t8.name}/.lattice/${t8.name}.md`
66343
- });
66379
+ };
66380
+ db.define(t8.name, def);
66381
+ memberEntityDefs.push({ name: t8.name, definition: def });
66344
66382
  }
66345
66383
  for (const { name } of views) {
66346
66384
  const base = name.slice(0, -2);
66347
66385
  if (knownTables.has(base)) maskedReadViews.set(base, name);
66348
66386
  }
66387
+ if (autoRender && memberEntityDefs.length > 0) {
66388
+ const existingContexts = db.entityContexts();
66389
+ for (const { table, definition } of deriveCanonicalContexts(memberEntityDefs)) {
66390
+ if (!existingContexts.has(table)) db.defineEntityContext(table, definition);
66391
+ }
66392
+ }
66349
66393
  }
66350
66394
  }
66351
66395
  } catch {
@@ -67836,9 +67880,18 @@ async function startGuiServer(options) {
67836
67880
  }
67837
67881
  const tables = [];
67838
67882
  for (const r6 of rows) {
67839
- const cols = await active.db.introspectColumns(r6.name);
67840
- const rowCount = await active.db.count(r6.name);
67841
- tables.push({ name: r6.name, columns: cols, rowCount });
67883
+ try {
67884
+ const cols = await active.db.introspectColumns(r6.name);
67885
+ const rowCount = await active.db.count(r6.name);
67886
+ tables.push({ name: r6.name, columns: cols, rowCount });
67887
+ } catch (err) {
67888
+ const msg = err instanceof Error ? err.message : String(err);
67889
+ if (/permission denied|does not exist/i.test(msg)) {
67890
+ tables.push({ name: r6.name, columns: [], rowCount: null });
67891
+ } else {
67892
+ throw err;
67893
+ }
67894
+ }
67842
67895
  }
67843
67896
  sendJson(res, { tables });
67844
67897
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "3.3.3",
3
+ "version": "3.3.4",
4
4
  "description": "Persistent structured memory for AI agent systems — pluggable SQLite or Postgres backend, LLM context bridge",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",