@threadbase-sh/streamer 1.52.5 → 1.53.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 +754 -467
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +228 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -6
- package/dist/index.d.ts +66 -6
- package/dist/index.js +225 -59
- package/dist/index.js.map +1 -1
- package/dist/migrations/011_create_devices.sql +15 -0
- package/dist/runtime-migrations/003_create_devices.sql +52 -0
- package/package.json +1 -1
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;
|