latticesql 3.4.5 → 3.4.6

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
@@ -10313,6 +10313,21 @@ var init_registry = __esm({
10313
10313
  ["table", "values"]
10314
10314
  )
10315
10315
  },
10316
+ {
10317
+ name: "create_secret",
10318
+ description: "Store a secret/credential \u2014 an API key, password, OAuth token, connection string, etc. \u2014 by name in the encrypted secrets store. Use this whenever the user gives you a credential to save or asks you to remember/store a secret. WRITE-ONLY: you can save a secret but you can NEVER read, list, echo, or retrieve existing secret values \u2014 they are hidden from you. The value is encrypted at rest.",
10319
+ mutates: true,
10320
+ category: "row",
10321
+ args: obj(
10322
+ {
10323
+ name: str('A short label for the secret, e.g. "GitHub password" or "OpenAI API key".'),
10324
+ value: str("The secret value to store."),
10325
+ kind: str('Optional kind, e.g. "password", "api_key", "token", "connection_string".'),
10326
+ description: str("Optional note about what the secret is for.")
10327
+ },
10328
+ ["name", "value"]
10329
+ )
10330
+ },
10316
10331
  {
10317
10332
  name: "create_artifact",
10318
10333
  description: "Create a markdown document and save it as a file artifact. Use this whenever the user asks you to create, write, draft, or make a document, note, write-up, summary, report, or file \u2014 you author the content as GitHub-flavored markdown and it is saved in the files entity as a markdown artifact, then opened in the viewer for them. Prefer this over create_row on files for any document the user wants to keep. It follows the same sharing rules as any file (private mode \u2192 private).",
@@ -13156,6 +13171,7 @@ var init_ingest_url = __esm({
13156
13171
  });
13157
13172
 
13158
13173
  // src/gui/ai/dispatch.ts
13174
+ import { randomUUID } from "crypto";
13159
13175
  function visibilityDenialReason(opts) {
13160
13176
  if (opts.kind === "table") {
13161
13177
  return opts.canManageTableDefault ? null : "Only the workspace owner can change a table's default sharing.";
@@ -13371,6 +13387,21 @@ async function executeFunction(ctx, name, args) {
13371
13387
  );
13372
13388
  return { ok: true, result: { id } };
13373
13389
  }
13390
+ case "create_secret": {
13391
+ const secretName = requireString(args.name, "name");
13392
+ const secretValue2 = requireString(args.value, "value");
13393
+ const kind = typeof args.kind === "string" && args.kind ? args.kind : null;
13394
+ const description = typeof args.description === "string" && args.description ? args.description : null;
13395
+ const id = randomUUID();
13396
+ await ctx.db.insert("secrets", {
13397
+ id,
13398
+ name: secretName,
13399
+ value: secretValue2,
13400
+ kind,
13401
+ description
13402
+ });
13403
+ return { ok: true, result: { id, name: secretName } };
13404
+ }
13374
13405
  case "create_artifact": {
13375
13406
  const table = requireTable("files", ctx.validTables);
13376
13407
  const title = requireString(args.title, "title");
@@ -13701,6 +13732,7 @@ var init_dispatch = __esm({
13701
13732
  "get_history",
13702
13733
  "create_row",
13703
13734
  "create_artifact",
13735
+ "create_secret",
13704
13736
  "ingest_url",
13705
13737
  "set_definition",
13706
13738
  "set_visibility",
@@ -64852,7 +64884,7 @@ function redeemInviteToken(email, token) {
64852
64884
  init_markdown();
64853
64885
  init_rls();
64854
64886
  init_adapter();
64855
- import { randomUUID } from "crypto";
64887
+ import { randomUUID as randomUUID2 } from "crypto";
64856
64888
 
64857
64889
  // src/framework/cloud-migration.ts
64858
64890
  init_lattice();
@@ -65647,7 +65679,7 @@ async function dispatchDbConfigRoute(req, res, ctx) {
65647
65679
  `INSERT INTO "__lattice_member_invites" ("id","role","email_hash","email","expires_at")
65648
65680
  VALUES (?, ?, ?, ?, ?)`,
65649
65681
  [
65650
- randomUUID(),
65682
+ randomUUID2(),
65651
65683
  role,
65652
65684
  emailHash,
65653
65685
  // Plaintext email stored ONLY in this owner-only table so the owner's
@@ -70221,7 +70253,7 @@ function printHelp() {
70221
70253
  );
70222
70254
  }
70223
70255
  function getVersion() {
70224
- if (true) return "3.4.5";
70256
+ if (true) return "3.4.6";
70225
70257
  try {
70226
70258
  const pkgPath = new URL("../package.json", import.meta.url).pathname;
70227
70259
  const pkg = JSON.parse(readFileSync20(pkgPath, "utf-8"));
package/dist/index.cjs CHANGED
@@ -50606,6 +50606,21 @@ var init_registry = __esm({
50606
50606
  ["table", "values"]
50607
50607
  )
50608
50608
  },
50609
+ {
50610
+ name: "create_secret",
50611
+ description: "Store a secret/credential \u2014 an API key, password, OAuth token, connection string, etc. \u2014 by name in the encrypted secrets store. Use this whenever the user gives you a credential to save or asks you to remember/store a secret. WRITE-ONLY: you can save a secret but you can NEVER read, list, echo, or retrieve existing secret values \u2014 they are hidden from you. The value is encrypted at rest.",
50612
+ mutates: true,
50613
+ category: "row",
50614
+ args: obj(
50615
+ {
50616
+ name: str('A short label for the secret, e.g. "GitHub password" or "OpenAI API key".'),
50617
+ value: str("The secret value to store."),
50618
+ kind: str('Optional kind, e.g. "password", "api_key", "token", "connection_string".'),
50619
+ description: str("Optional note about what the secret is for.")
50620
+ },
50621
+ ["name", "value"]
50622
+ )
50623
+ },
50609
50624
  {
50610
50625
  name: "create_artifact",
50611
50626
  description: "Create a markdown document and save it as a file artifact. Use this whenever the user asks you to create, write, draft, or make a document, note, write-up, summary, report, or file \u2014 you author the content as GitHub-flavored markdown and it is saved in the files entity as a markdown artifact, then opened in the viewer for them. Prefer this over create_row on files for any document the user wants to keep. It follows the same sharing rules as any file (private mode \u2192 private).",
@@ -53028,6 +53043,21 @@ async function executeFunction(ctx, name, args) {
53028
53043
  );
53029
53044
  return { ok: true, result: { id } };
53030
53045
  }
53046
+ case "create_secret": {
53047
+ const secretName = requireString(args.name, "name");
53048
+ const secretValue2 = requireString(args.value, "value");
53049
+ const kind = typeof args.kind === "string" && args.kind ? args.kind : null;
53050
+ const description = typeof args.description === "string" && args.description ? args.description : null;
53051
+ const id = (0, import_node_crypto18.randomUUID)();
53052
+ await ctx.db.insert("secrets", {
53053
+ id,
53054
+ name: secretName,
53055
+ value: secretValue2,
53056
+ kind,
53057
+ description
53058
+ });
53059
+ return { ok: true, result: { id, name: secretName } };
53060
+ }
53031
53061
  case "create_artifact": {
53032
53062
  const table = requireTable("files", ctx.validTables);
53033
53063
  const title = requireString(args.title, "title");
@@ -53331,10 +53361,11 @@ async function executeFunction(ctx, name, args) {
53331
53361
  return { ok: false, error: e6.message };
53332
53362
  }
53333
53363
  }
53334
- var DISPATCHABLE, ASSISTANT_HIDDEN_TABLES, SECRET_MASK, BULK_FILTER_OPS;
53364
+ var import_node_crypto18, DISPATCHABLE, ASSISTANT_HIDDEN_TABLES, SECRET_MASK, BULK_FILTER_OPS;
53335
53365
  var init_dispatch = __esm({
53336
53366
  "src/gui/ai/dispatch.ts"() {
53337
53367
  "use strict";
53368
+ import_node_crypto18 = require("crypto");
53338
53369
  init_registry();
53339
53370
  init_lattice_docs();
53340
53371
  init_fts();
@@ -53358,6 +53389,7 @@ var init_dispatch = __esm({
53358
53389
  "get_history",
53359
53390
  "create_row",
53360
53391
  "create_artifact",
53392
+ "create_secret",
53361
53393
  "ingest_url",
53362
53394
  "set_definition",
53363
53395
  "set_visibility",
@@ -66322,11 +66354,11 @@ var import_yaml6 = require("yaml");
66322
66354
  init_lattice();
66323
66355
  init_user_config();
66324
66356
  init_cloud_connect();
66325
- var import_node_crypto19 = require("crypto");
66357
+ var import_node_crypto20 = require("crypto");
66326
66358
  init_members();
66327
66359
 
66328
66360
  // src/cloud/invite.ts
66329
- var import_node_crypto18 = require("crypto");
66361
+ var import_node_crypto19 = require("crypto");
66330
66362
  var VERSION = 1;
66331
66363
  var SALT_LEN = 16;
66332
66364
  var SECRET_LEN = 32;
@@ -66344,15 +66376,15 @@ function poolerAwareUser(host, role, ownerUser) {
66344
66376
  return ref ? `${role}.${ref}` : role;
66345
66377
  }
66346
66378
  function deriveKey2(tokenSecret, email, salt) {
66347
- const emailSalt = Buffer.from((0, import_node_crypto18.scryptSync)(normalizeEmail(email), salt, KEY_LEN));
66348
- return Buffer.from((0, import_node_crypto18.hkdfSync)("sha256", tokenSecret, emailSalt, HKDF_INFO, KEY_LEN));
66379
+ const emailSalt = Buffer.from((0, import_node_crypto19.scryptSync)(normalizeEmail(email), salt, KEY_LEN));
66380
+ return Buffer.from((0, import_node_crypto19.hkdfSync)("sha256", tokenSecret, emailSalt, HKDF_INFO, KEY_LEN));
66349
66381
  }
66350
66382
  function mintInviteToken(input) {
66351
66383
  const email = normalizeEmail(input.email);
66352
66384
  if (!email) throw new Error("lattice: an invite must be bound to an email");
66353
- const salt = (0, import_node_crypto18.randomBytes)(SALT_LEN);
66354
- const tokenSecret = (0, import_node_crypto18.randomBytes)(SECRET_LEN);
66355
- const nonce = (0, import_node_crypto18.randomBytes)(NONCE_LEN);
66385
+ const salt = (0, import_node_crypto19.randomBytes)(SALT_LEN);
66386
+ const tokenSecret = (0, import_node_crypto19.randomBytes)(SECRET_LEN);
66387
+ const nonce = (0, import_node_crypto19.randomBytes)(NONCE_LEN);
66356
66388
  const key = deriveKey2(tokenSecret, email, salt);
66357
66389
  const payload = {
66358
66390
  v: 1,
@@ -66366,7 +66398,7 @@ function mintInviteToken(input) {
66366
66398
  expires_at: input.expiresAt.toISOString(),
66367
66399
  ...input.workspaceName?.trim() ? { workspace_name: input.workspaceName.trim() } : {}
66368
66400
  };
66369
- const cipher = (0, import_node_crypto18.createCipheriv)("aes-256-gcm", key, nonce);
66401
+ const cipher = (0, import_node_crypto19.createCipheriv)("aes-256-gcm", key, nonce);
66370
66402
  cipher.setAAD(Buffer.from(email, "utf8"));
66371
66403
  const ct = Buffer.concat([cipher.update(JSON.stringify(payload), "utf8"), cipher.final()]);
66372
66404
  const tag = cipher.getAuthTag();
@@ -66389,7 +66421,7 @@ function redeemInviteToken(email, token) {
66389
66421
  const tag = raw.subarray(raw.length - TAG_LEN2);
66390
66422
  const ct = raw.subarray(off, raw.length - TAG_LEN2);
66391
66423
  const key = deriveKey2(tokenSecret, normEmail, salt);
66392
- const decipher = (0, import_node_crypto18.createDecipheriv)("aes-256-gcm", key, nonce);
66424
+ const decipher = (0, import_node_crypto19.createDecipheriv)("aes-256-gcm", key, nonce);
66393
66425
  decipher.setAAD(Buffer.from(normEmail, "utf8"));
66394
66426
  decipher.setAuthTag(tag);
66395
66427
  let plaintext;
@@ -66417,7 +66449,7 @@ function redeemInviteToken(email, token) {
66417
66449
  init_markdown();
66418
66450
  init_rls();
66419
66451
  init_adapter();
66420
- var import_node_crypto20 = require("crypto");
66452
+ var import_node_crypto21 = require("crypto");
66421
66453
  init_parser();
66422
66454
  init_lattice_root();
66423
66455
  init_workspace();
@@ -66502,7 +66534,7 @@ function parseAndValidateLogo(dataUri) {
66502
66534
  error: `logo must be square (got ${String(dims.width)}\xD7${String(dims.height)})`
66503
66535
  };
66504
66536
  }
66505
- return { ok: true, mime, bytes, etag: (0, import_node_crypto19.createHash)("sha256").update(bytes).digest("hex") };
66537
+ return { ok: true, mime, bytes, etag: (0, import_node_crypto20.createHash)("sha256").update(bytes).digest("hex") };
66506
66538
  }
66507
66539
  function updateActiveWorkspaceToCloud(configPath, displayName, key) {
66508
66540
  const root6 = findLatticeRoot((0, import_node_path36.dirname)(configPath));
@@ -67012,7 +67044,7 @@ async function dispatchDbConfigRoute(req, res, ctx) {
67012
67044
  `INSERT INTO "__lattice_member_invites" ("id","role","email_hash","email","expires_at")
67013
67045
  VALUES (?, ?, ?, ?, ?)`,
67014
67046
  [
67015
- (0, import_node_crypto20.randomUUID)(),
67047
+ (0, import_node_crypto21.randomUUID)(),
67016
67048
  role,
67017
67049
  emailHash,
67018
67050
  // Plaintext email stored ONLY in this owner-only table so the owner's
@@ -67838,7 +67870,7 @@ var import_node_os9 = require("os");
67838
67870
  var import_node_path37 = require("path");
67839
67871
  init_mutations();
67840
67872
  init_extract();
67841
- var import_node_crypto21 = require("crypto");
67873
+ var import_node_crypto22 = require("crypto");
67842
67874
  init_assistant_routes();
67843
67875
  init_enrich();
67844
67876
  init_ingest_url();
@@ -68079,7 +68111,7 @@ async function dispatchIngestRoute(req, res, ctx) {
68079
68111
  let s3Status = null;
68080
68112
  const s3cfg = resolveActiveS3Config(ctx.configPath);
68081
68113
  if (s3cfg) {
68082
- const sha256 = blob?.sha256 ?? (0, import_node_crypto21.createHash)("sha256").update(buf).digest("hex");
68114
+ const sha256 = blob?.sha256 ?? (0, import_node_crypto22.createHash)("sha256").update(buf).digest("hex");
68083
68115
  const key = s3Key(s3cfg.prefix, sha256);
68084
68116
  try {
68085
68117
  const store = await createS3Store(s3cfg);
@@ -68111,7 +68143,7 @@ async function dispatchIngestRoute(req, res, ctx) {
68111
68143
  realPath = rawFilePath;
68112
68144
  }
68113
68145
  }
68114
- const fileSha = blob?.sha256 ?? s3Ref?.sha256 ?? (0, import_node_crypto21.createHash)("sha256").update(buf).digest("hex");
68146
+ const fileSha = blob?.sha256 ?? s3Ref?.sha256 ?? (0, import_node_crypto22.createHash)("sha256").update(buf).digest("hex");
68115
68147
  const uploadRow = {
68116
68148
  id: fileId,
68117
68149
  ...fileIdentity(name2, fileId),
@@ -71200,7 +71232,7 @@ ${e6.stack ?? ""}`
71200
71232
  // src/cloud/file-source-key-store.ts
71201
71233
  var import_node_fs36 = require("fs");
71202
71234
  var import_node_path39 = require("path");
71203
- var import_node_crypto22 = require("crypto");
71235
+ var import_node_crypto23 = require("crypto");
71204
71236
  var ENC_HEADER = "LATTICE-KMS-v1\n";
71205
71237
  var SCRYPT_N = 1 << 15;
71206
71238
  var SCRYPT_R = 8;
@@ -71227,7 +71259,7 @@ var FileSourceKeyStore = class {
71227
71259
  getOrCreate(sourceId) {
71228
71260
  let key = this.cache.get(sourceId);
71229
71261
  if (!key) {
71230
- key = (0, import_node_crypto22.randomBytes)(KEY_LEN2);
71262
+ key = (0, import_node_crypto23.randomBytes)(KEY_LEN2);
71231
71263
  this.cache.set(sourceId, key);
71232
71264
  this.persist();
71233
71265
  }
@@ -71271,7 +71303,7 @@ var FileSourceKeyStore = class {
71271
71303
  const obj2 = {};
71272
71304
  for (const [k6, v2] of this.cache) obj2[k6] = v2.toString("base64");
71273
71305
  const encoded = this.encodeFile(obj2);
71274
- const tmpPath = `${this.path}.tmp-${process.pid.toString()}-${(0, import_node_crypto22.randomBytes)(4).toString("hex")}`;
71306
+ const tmpPath = `${this.path}.tmp-${process.pid.toString()}-${(0, import_node_crypto23.randomBytes)(4).toString("hex")}`;
71275
71307
  (0, import_node_fs36.writeFileSync)(tmpPath, encoded, { mode: 384 });
71276
71308
  try {
71277
71309
  (0, import_node_fs36.chmodSync)(tmpPath, 384);
@@ -71314,14 +71346,14 @@ var FileSourceKeyStore = class {
71314
71346
  if (passphrase === void 0) {
71315
71347
  throw new Error("lattice: key file is encrypted but no passphrase was configured");
71316
71348
  }
71317
- const derived = (0, import_node_crypto22.scryptSync)(passphrase, salt, KEY_LEN2, {
71349
+ const derived = (0, import_node_crypto23.scryptSync)(passphrase, salt, KEY_LEN2, {
71318
71350
  N: SCRYPT_N,
71319
71351
  r: SCRYPT_R,
71320
71352
  p: SCRYPT_P,
71321
71353
  maxmem: 64 * 1024 * 1024
71322
71354
  // raise Node's default 32MB cap so N=2^15 fits
71323
71355
  });
71324
- const decipher = (0, import_node_crypto22.createDecipheriv)("aes-256-gcm", derived, iv);
71356
+ const decipher = (0, import_node_crypto23.createDecipheriv)("aes-256-gcm", derived, iv);
71325
71357
  decipher.setAuthTag(tag);
71326
71358
  let plaintext;
71327
71359
  try {
@@ -71336,15 +71368,15 @@ var FileSourceKeyStore = class {
71336
71368
  if (!this.passphrase) {
71337
71369
  return Buffer.from(json, "utf8");
71338
71370
  }
71339
- const salt = (0, import_node_crypto22.randomBytes)(SALT_LEN2);
71340
- const iv = (0, import_node_crypto22.randomBytes)(IV_LEN2);
71341
- const derived = (0, import_node_crypto22.scryptSync)(this.passphrase, salt, KEY_LEN2, {
71371
+ const salt = (0, import_node_crypto23.randomBytes)(SALT_LEN2);
71372
+ const iv = (0, import_node_crypto23.randomBytes)(IV_LEN2);
71373
+ const derived = (0, import_node_crypto23.scryptSync)(this.passphrase, salt, KEY_LEN2, {
71342
71374
  N: SCRYPT_N,
71343
71375
  r: SCRYPT_R,
71344
71376
  p: SCRYPT_P,
71345
71377
  maxmem: 64 * 1024 * 1024
71346
71378
  });
71347
- const cipher = (0, import_node_crypto22.createCipheriv)("aes-256-gcm", derived, iv);
71379
+ const cipher = (0, import_node_crypto23.createCipheriv)("aes-256-gcm", derived, iv);
71348
71380
  const ct = Buffer.concat([cipher.update(json, "utf8"), cipher.final()]);
71349
71381
  const tag = cipher.getAuthTag();
71350
71382
  const body = `${salt.toString("hex")}:${iv.toString("hex")}:${Buffer.concat([ct, tag]).toString("hex")}`;
package/dist/index.js CHANGED
@@ -50597,6 +50597,21 @@ var init_registry = __esm({
50597
50597
  ["table", "values"]
50598
50598
  )
50599
50599
  },
50600
+ {
50601
+ name: "create_secret",
50602
+ description: "Store a secret/credential \u2014 an API key, password, OAuth token, connection string, etc. \u2014 by name in the encrypted secrets store. Use this whenever the user gives you a credential to save or asks you to remember/store a secret. WRITE-ONLY: you can save a secret but you can NEVER read, list, echo, or retrieve existing secret values \u2014 they are hidden from you. The value is encrypted at rest.",
50603
+ mutates: true,
50604
+ category: "row",
50605
+ args: obj(
50606
+ {
50607
+ name: str('A short label for the secret, e.g. "GitHub password" or "OpenAI API key".'),
50608
+ value: str("The secret value to store."),
50609
+ kind: str('Optional kind, e.g. "password", "api_key", "token", "connection_string".'),
50610
+ description: str("Optional note about what the secret is for.")
50611
+ },
50612
+ ["name", "value"]
50613
+ )
50614
+ },
50600
50615
  {
50601
50616
  name: "create_artifact",
50602
50617
  description: "Create a markdown document and save it as a file artifact. Use this whenever the user asks you to create, write, draft, or make a document, note, write-up, summary, report, or file \u2014 you author the content as GitHub-flavored markdown and it is saved in the files entity as a markdown artifact, then opened in the viewer for them. Prefer this over create_row on files for any document the user wants to keep. It follows the same sharing rules as any file (private mode \u2192 private).",
@@ -52803,6 +52818,7 @@ var init_ingest_url = __esm({
52803
52818
  });
52804
52819
 
52805
52820
  // src/gui/ai/dispatch.ts
52821
+ import { randomUUID } from "crypto";
52806
52822
  function visibilityDenialReason(opts) {
52807
52823
  if (opts.kind === "table") {
52808
52824
  return opts.canManageTableDefault ? null : "Only the workspace owner can change a table's default sharing.";
@@ -53018,6 +53034,21 @@ async function executeFunction(ctx, name, args) {
53018
53034
  );
53019
53035
  return { ok: true, result: { id } };
53020
53036
  }
53037
+ case "create_secret": {
53038
+ const secretName = requireString(args.name, "name");
53039
+ const secretValue2 = requireString(args.value, "value");
53040
+ const kind = typeof args.kind === "string" && args.kind ? args.kind : null;
53041
+ const description = typeof args.description === "string" && args.description ? args.description : null;
53042
+ const id = randomUUID();
53043
+ await ctx.db.insert("secrets", {
53044
+ id,
53045
+ name: secretName,
53046
+ value: secretValue2,
53047
+ kind,
53048
+ description
53049
+ });
53050
+ return { ok: true, result: { id, name: secretName } };
53051
+ }
53021
53052
  case "create_artifact": {
53022
53053
  const table = requireTable("files", ctx.validTables);
53023
53054
  const title = requireString(args.title, "title");
@@ -53348,6 +53379,7 @@ var init_dispatch = __esm({
53348
53379
  "get_history",
53349
53380
  "create_row",
53350
53381
  "create_artifact",
53382
+ "create_secret",
53351
53383
  "ingest_url",
53352
53384
  "set_definition",
53353
53385
  "set_visibility",
@@ -66241,7 +66273,7 @@ function redeemInviteToken(email, token) {
66241
66273
  init_markdown();
66242
66274
  init_rls();
66243
66275
  init_adapter();
66244
- import { randomUUID } from "crypto";
66276
+ import { randomUUID as randomUUID2 } from "crypto";
66245
66277
  init_parser();
66246
66278
  init_lattice_root();
66247
66279
  init_workspace();
@@ -66836,7 +66868,7 @@ async function dispatchDbConfigRoute(req, res, ctx) {
66836
66868
  `INSERT INTO "__lattice_member_invites" ("id","role","email_hash","email","expires_at")
66837
66869
  VALUES (?, ?, ?, ?, ?)`,
66838
66870
  [
66839
- randomUUID(),
66871
+ randomUUID2(),
66840
66872
  role,
66841
66873
  emailHash,
66842
66874
  // Plaintext email stored ONLY in this owner-only table so the owner's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "3.4.5",
3
+ "version": "3.4.6",
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",