@threadbase-sh/streamer 1.56.0 → 1.58.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/dist/cli.cjs CHANGED
@@ -97011,7 +97011,12 @@ function toDeviceView(row) {
97011
97011
  capabilities: parseCapabilities(row.capabilities),
97012
97012
  createdAt: row.created_at,
97013
97013
  lastSeenAt: row.last_seen_at,
97014
- revokedAt: row.revoked_at
97014
+ revokedAt: row.revoked_at,
97015
+ // Reported from `e2ee_required` rather than from the key's presence. The
97016
+ // two agree today, but they answer different questions — the key is what a
97017
+ // handshake is checked against, `e2ee_required` is whether plaintext is
97018
+ // refused — and it is the second one a user is asking about.
97019
+ e2ee: row.e2ee_required === 1
97015
97020
  };
97016
97021
  }
97017
97022
  var import_crypto3, DevicesRepository;
@@ -97029,13 +97034,29 @@ var init_devices_repository = __esm({
97029
97034
  touchStmt;
97030
97035
  deleteStmt;
97031
97036
  deleteRevokedStmt;
97037
+ byE2eeStaticPubStmt;
97038
+ repairStmt;
97032
97039
  constructor(db) {
97033
97040
  this.insertStmt = db.prepare(`
97034
97041
  INSERT INTO devices (
97035
- device_id, public_key, token_hash, name, capabilities, created_at
97042
+ device_id, public_key, token_hash, name, capabilities, created_at,
97043
+ e2ee_static_pub, e2ee_required, e2ee_version
97036
97044
  ) VALUES (
97037
- @device_id, @public_key, @token_hash, @name, @capabilities, @created_at
97045
+ @device_id, @public_key, @token_hash, @name, @capabilities, @created_at,
97046
+ @e2ee_static_pub, @e2ee_required, @e2ee_version
97038
97047
  )
97048
+ `);
97049
+ this.byE2eeStaticPubStmt = db.prepare("SELECT * FROM devices WHERE e2ee_static_pub = ?");
97050
+ this.repairStmt = db.prepare(`
97051
+ UPDATE devices SET
97052
+ public_key = @public_key,
97053
+ token_hash = @token_hash,
97054
+ name = @name,
97055
+ capabilities = @capabilities,
97056
+ e2ee_required = 1,
97057
+ e2ee_version = @e2ee_version,
97058
+ revoked_at = NULL
97059
+ WHERE device_id = @device_id
97039
97060
  `);
97040
97061
  this.byTokenHashStmt = db.prepare("SELECT * FROM devices WHERE token_hash = ?");
97041
97062
  this.byIdStmt = db.prepare("SELECT * FROM devices WHERE device_id = ?");
@@ -97052,19 +97073,42 @@ var init_devices_repository = __esm({
97052
97073
  * moment it exists outside the client.
97053
97074
  */
97054
97075
  register(args) {
97055
- const deviceId = (0, import_crypto3.randomUUID)();
97056
97076
  const deviceToken = generateDeviceToken();
97057
97077
  const capabilities = capabilitiesForPreset(args.preset ?? "full");
97078
+ const now = args.now ?? Date.now();
97079
+ const existing = args.e2eeStaticPub ? this.byE2eeStaticPubStmt.get(args.e2eeStaticPub) : void 0;
97080
+ if (existing) {
97081
+ this.repairStmt.run({
97082
+ device_id: existing.device_id,
97083
+ public_key: args.publicKey,
97084
+ token_hash: hashDeviceToken(deviceToken),
97085
+ name: args.name ?? null,
97086
+ capabilities: JSON.stringify(capabilities),
97087
+ e2ee_version: args.e2eeVersion ?? null
97088
+ });
97089
+ return { deviceId: existing.device_id, deviceToken, capabilities };
97090
+ }
97091
+ const deviceId = (0, import_crypto3.randomUUID)();
97058
97092
  this.insertStmt.run({
97059
97093
  device_id: deviceId,
97060
97094
  public_key: args.publicKey,
97061
97095
  token_hash: hashDeviceToken(deviceToken),
97062
97096
  name: args.name ?? null,
97063
97097
  capabilities: JSON.stringify(capabilities),
97064
- created_at: args.now ?? Date.now()
97098
+ created_at: now,
97099
+ e2ee_static_pub: args.e2eeStaticPub ?? null,
97100
+ // The downgrade lock, set in the same write that records the key. Once
97101
+ // set, nothing a client can send clears it (design.md §6.3) — which is
97102
+ // what makes it a lock rather than a preference.
97103
+ e2ee_required: args.e2eeStaticPub ? 1 : 0,
97104
+ e2ee_version: args.e2eeVersion ?? null
97065
97105
  });
97066
97106
  return { deviceId, deviceToken, capabilities };
97067
97107
  }
97108
+ /** The device that owns a Noise static key, or null. */
97109
+ getByE2eeStaticPub(staticPub) {
97110
+ return this.byE2eeStaticPubStmt.get(staticPub) ?? null;
97111
+ }
97068
97112
  /**
97069
97113
  * Resolve a presented token to a device, or null.
97070
97114
  *
@@ -145659,6 +145703,7 @@ function readBody2(req) {
145659
145703
  // src/api/handlers/conversations.handlers.ts
145660
145704
  var SEARCH_OVERFETCH = 4;
145661
145705
  var SEARCH_MAX_SCAN = 1e3;
145706
+ var MAX_BYTES_CEILING = 32 * 1024 * 1024;
145662
145707
  var ConversationHandlers = class {
145663
145708
  constructor(deps) {
145664
145709
  this.deps = deps;
@@ -146064,7 +146109,7 @@ var ConversationHandlers = class {
146064
146109
  const total = filtered.length;
146065
146110
  const hasAnchor = url2.searchParams.has("anchor_index");
146066
146111
  const hasAfter = url2.searchParams.has("after_index");
146067
- const usePaging = url2.searchParams.has("msg_limit") || url2.searchParams.has("before_index") || hasAnchor || hasAfter;
146112
+ const usePaging = url2.searchParams.has("msg_limit") || url2.searchParams.has("before_index") || url2.searchParams.has("max_bytes") || hasAnchor || hasAfter;
146068
146113
  let slice = filtered;
146069
146114
  let fromIdx = 0;
146070
146115
  let messagePagination;
@@ -146186,6 +146231,28 @@ var ConversationHandlers = class {
146186
146231
  content
146187
146232
  };
146188
146233
  });
146234
+ const requestedMaxBytes = intParam(url2, "max_bytes", 0);
146235
+ if (requestedMaxBytes > 0 && messagesPayload.length > 0) {
146236
+ const budget = Math.min(requestedMaxBytes, MAX_BYTES_CEILING);
146237
+ let used = 0;
146238
+ let firstKept = messagesPayload.length - 1;
146239
+ for (let i = messagesPayload.length - 1; i >= 0; i--) {
146240
+ const size = Buffer.byteLength(JSON.stringify(messagesPayload[i]));
146241
+ if (i < messagesPayload.length - 1 && used + size > budget) break;
146242
+ used += size;
146243
+ firstKept = i;
146244
+ }
146245
+ if (firstKept > 0) {
146246
+ messagesPayload.splice(0, firstKept);
146247
+ if (messagePagination) {
146248
+ const newFrom = fromIdx + firstKept;
146249
+ messagePagination.from_index = newFrom;
146250
+ messagePagination.has_more_older = newFrom > 0;
146251
+ messagePagination.next_before_index = newFrom > 0 ? newFrom : null;
146252
+ }
146253
+ }
146254
+ if (messagePagination) messagePagination.served_bytes = used;
146255
+ }
146189
146256
  const conv = conversation;
146190
146257
  const cachedConvMeta = this.cache?.getMetaById(id);
146191
146258
  const convProvider = coerceProviderForRunner(conv.provider ?? cachedConvMeta?.provider);