@threadbase-sh/streamer 1.52.4 → 1.52.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/index.d.cts CHANGED
@@ -1136,6 +1136,8 @@ declare class DevicesRepository {
1136
1136
  private listStmt;
1137
1137
  private revokeStmt;
1138
1138
  private touchStmt;
1139
+ private deleteStmt;
1140
+ private deleteRevokedStmt;
1139
1141
  constructor(db: Database.Database);
1140
1142
  /**
1141
1143
  * Record a newly paired device and mint its token.
@@ -1161,6 +1163,29 @@ declare class DevicesRepository {
1161
1163
  list(): DeviceView[];
1162
1164
  /** Revoke one device. Others are untouched — no key rotation, no collateral. */
1163
1165
  revoke(deviceId: string, now?: number): boolean;
1166
+ /**
1167
+ * Erase one device's record outright.
1168
+ *
1169
+ * Deliberately separate from `revoke`, which is a soft delete that keeps the
1170
+ * row so `list()` can show what happened. That audit trail is the right
1171
+ * default — but it meant a `devices` row, including the user-supplied `name`
1172
+ * ("Ronen's iPhone"), had no removal path at all once the registry moved to
1173
+ * runtime.db, which no command deletes. This is that path.
1174
+ *
1175
+ * Erasure is NOT revocation: deleting a row frees its `token_hash`, so a
1176
+ * device whose token is still on a phone somewhere stops being *known* rather
1177
+ * than being *refused*. Revoke first, delete second, is the safe order, and
1178
+ * `deleteRevoked()` exists so that is the easy thing to do.
1179
+ */
1180
+ delete(deviceId: string): boolean;
1181
+ /**
1182
+ * Erase every already-revoked device. The bulk companion to `delete`, and the
1183
+ * one that is safe by construction: a revoked device is already refused, so
1184
+ * removing its row cannot restore access to anything.
1185
+ *
1186
+ * Returns the number of rows removed.
1187
+ */
1188
+ deleteRevoked(): number;
1164
1189
  touch(deviceId: string, now?: number): void;
1165
1190
  }
1166
1191
 
@@ -1547,14 +1572,49 @@ declare class RuntimeStore {
1547
1572
  /**
1548
1573
  * One-time move of `managed_sessions` rows out of a pre-split `cache.db`.
1549
1574
  *
1550
- * Non-destructive by design: the source table is left in place so an older
1551
- * streamer rolled back onto the same machine still finds its registry. Runs
1552
- * only when this file's table is empty, so a second boot is a no-op rather
1553
- * than a re-copy that would resurrect rows deleted since.
1554
- *
1555
1575
  * Returns the number of rows copied.
1556
1576
  */
1557
1577
  importLegacyManagedSessions(source: Database.Database): number;
1578
+ /**
1579
+ * One-time move of `devices` rows out of `cache.db`, where the registry used
1580
+ * to live (migration `011_create_devices.sql`).
1581
+ *
1582
+ * Losing this table invalidates every device token ever issued, and cache.db
1583
+ * is the file `tb-streamer cache clear` deletes and the integrity monitor
1584
+ * rebuilds — see `runtime-migrations/003_create_devices.sql`.
1585
+ *
1586
+ * Unlike `managed_sessions`, this one MOVES rather than copies: the source
1587
+ * rows are deleted once the copy is verified. A `devices` row carries a
1588
+ * user-supplied label ("Ronen's iPhone"), and leaving a second copy of that
1589
+ * on disk indefinitely — in the one file the user is told to delete when
1590
+ * something goes wrong — is more retained personal data than the rollback
1591
+ * path is worth. Recovering from a rollback is re-scanning a pairing QR.
1592
+ *
1593
+ * The delete is conditional on the copy being complete: `INSERT OR IGNORE`
1594
+ * can silently skip a row, so the destination count must match what was read
1595
+ * before anything is removed. A mismatch keeps the source and reports
1596
+ * `purged: false` rather than throwing — the import itself still succeeded,
1597
+ * and keeping data is the safe direction to fail in.
1598
+ */
1599
+ importLegacyDevices(source: Database.Database): {
1600
+ copied: number;
1601
+ purged: boolean;
1602
+ };
1603
+ /**
1604
+ * Copy a whole table out of a pre-split `cache.db` into this file.
1605
+ *
1606
+ * The copy itself is non-destructive — the source is left in place, so an
1607
+ * older streamer rolled back onto the same machine still finds its data.
1608
+ * `importLegacyDevices` deletes the source afterwards for its own reasons;
1609
+ * `managed_sessions` does not. Runs only when this file's table is empty, so
1610
+ * a second boot is a no-op rather than a re-copy that would resurrect rows
1611
+ * deleted since.
1612
+ *
1613
+ * The table name is interpolated into SQL, so it is typed as a closed union
1614
+ * rather than `string` — the set of tables that can ever be lifted is known
1615
+ * at compile time, and that is what keeps a caller from making this a hole.
1616
+ */
1617
+ private importLegacyTable;
1558
1618
  close(): void;
1559
1619
  }
1560
1620
 
@@ -1805,7 +1865,7 @@ type ApiDeps = {
1805
1865
  handleBrowse: (url: URL, res: ServerResponse) => Promise<void>;
1806
1866
  handleMkdir: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
1807
1867
  handleWsOpen: (ws: WebSocket) => void;
1808
- handleWsMessage: (ws: WebSocket, raw: unknown) => void;
1868
+ handleWsMessage: (ws: WebSocket, raw: unknown, principal: Principal | null) => void;
1809
1869
  handleWsClose: (ws: WebSocket) => void;
1810
1870
  agentClient: AgentClient | null;
1811
1871
  conversationWriter: ConversationWriter | null;
package/dist/index.d.ts CHANGED
@@ -1136,6 +1136,8 @@ declare class DevicesRepository {
1136
1136
  private listStmt;
1137
1137
  private revokeStmt;
1138
1138
  private touchStmt;
1139
+ private deleteStmt;
1140
+ private deleteRevokedStmt;
1139
1141
  constructor(db: Database.Database);
1140
1142
  /**
1141
1143
  * Record a newly paired device and mint its token.
@@ -1161,6 +1163,29 @@ declare class DevicesRepository {
1161
1163
  list(): DeviceView[];
1162
1164
  /** Revoke one device. Others are untouched — no key rotation, no collateral. */
1163
1165
  revoke(deviceId: string, now?: number): boolean;
1166
+ /**
1167
+ * Erase one device's record outright.
1168
+ *
1169
+ * Deliberately separate from `revoke`, which is a soft delete that keeps the
1170
+ * row so `list()` can show what happened. That audit trail is the right
1171
+ * default — but it meant a `devices` row, including the user-supplied `name`
1172
+ * ("Ronen's iPhone"), had no removal path at all once the registry moved to
1173
+ * runtime.db, which no command deletes. This is that path.
1174
+ *
1175
+ * Erasure is NOT revocation: deleting a row frees its `token_hash`, so a
1176
+ * device whose token is still on a phone somewhere stops being *known* rather
1177
+ * than being *refused*. Revoke first, delete second, is the safe order, and
1178
+ * `deleteRevoked()` exists so that is the easy thing to do.
1179
+ */
1180
+ delete(deviceId: string): boolean;
1181
+ /**
1182
+ * Erase every already-revoked device. The bulk companion to `delete`, and the
1183
+ * one that is safe by construction: a revoked device is already refused, so
1184
+ * removing its row cannot restore access to anything.
1185
+ *
1186
+ * Returns the number of rows removed.
1187
+ */
1188
+ deleteRevoked(): number;
1164
1189
  touch(deviceId: string, now?: number): void;
1165
1190
  }
1166
1191
 
@@ -1547,14 +1572,49 @@ declare class RuntimeStore {
1547
1572
  /**
1548
1573
  * One-time move of `managed_sessions` rows out of a pre-split `cache.db`.
1549
1574
  *
1550
- * Non-destructive by design: the source table is left in place so an older
1551
- * streamer rolled back onto the same machine still finds its registry. Runs
1552
- * only when this file's table is empty, so a second boot is a no-op rather
1553
- * than a re-copy that would resurrect rows deleted since.
1554
- *
1555
1575
  * Returns the number of rows copied.
1556
1576
  */
1557
1577
  importLegacyManagedSessions(source: Database.Database): number;
1578
+ /**
1579
+ * One-time move of `devices` rows out of `cache.db`, where the registry used
1580
+ * to live (migration `011_create_devices.sql`).
1581
+ *
1582
+ * Losing this table invalidates every device token ever issued, and cache.db
1583
+ * is the file `tb-streamer cache clear` deletes and the integrity monitor
1584
+ * rebuilds — see `runtime-migrations/003_create_devices.sql`.
1585
+ *
1586
+ * Unlike `managed_sessions`, this one MOVES rather than copies: the source
1587
+ * rows are deleted once the copy is verified. A `devices` row carries a
1588
+ * user-supplied label ("Ronen's iPhone"), and leaving a second copy of that
1589
+ * on disk indefinitely — in the one file the user is told to delete when
1590
+ * something goes wrong — is more retained personal data than the rollback
1591
+ * path is worth. Recovering from a rollback is re-scanning a pairing QR.
1592
+ *
1593
+ * The delete is conditional on the copy being complete: `INSERT OR IGNORE`
1594
+ * can silently skip a row, so the destination count must match what was read
1595
+ * before anything is removed. A mismatch keeps the source and reports
1596
+ * `purged: false` rather than throwing — the import itself still succeeded,
1597
+ * and keeping data is the safe direction to fail in.
1598
+ */
1599
+ importLegacyDevices(source: Database.Database): {
1600
+ copied: number;
1601
+ purged: boolean;
1602
+ };
1603
+ /**
1604
+ * Copy a whole table out of a pre-split `cache.db` into this file.
1605
+ *
1606
+ * The copy itself is non-destructive — the source is left in place, so an
1607
+ * older streamer rolled back onto the same machine still finds its data.
1608
+ * `importLegacyDevices` deletes the source afterwards for its own reasons;
1609
+ * `managed_sessions` does not. Runs only when this file's table is empty, so
1610
+ * a second boot is a no-op rather than a re-copy that would resurrect rows
1611
+ * deleted since.
1612
+ *
1613
+ * The table name is interpolated into SQL, so it is typed as a closed union
1614
+ * rather than `string` — the set of tables that can ever be lifted is known
1615
+ * at compile time, and that is what keeps a caller from making this a hole.
1616
+ */
1617
+ private importLegacyTable;
1558
1618
  close(): void;
1559
1619
  }
1560
1620
 
@@ -1805,7 +1865,7 @@ type ApiDeps = {
1805
1865
  handleBrowse: (url: URL, res: ServerResponse) => Promise<void>;
1806
1866
  handleMkdir: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
1807
1867
  handleWsOpen: (ws: WebSocket) => void;
1808
- handleWsMessage: (ws: WebSocket, raw: unknown) => void;
1868
+ handleWsMessage: (ws: WebSocket, raw: unknown, principal: Principal | null) => void;
1809
1869
  handleWsClose: (ws: WebSocket) => void;
1810
1870
  agentClient: AgentClient | null;
1811
1871
  conversationWriter: ConversationWriter | null;