@peers-app/peers-sdk 0.30.2 → 0.30.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.
@@ -0,0 +1,169 @@
1
+ /** Trigger for an overlapping, at most five-minute connectivity measurement. */
2
+ export type MeshEpisodeReason = "startup" | "resume" | "network-change" | "connection-loss";
3
+ /** Provenance of a dial; explicit requests and group joins are also distinguished. */
4
+ export type MeshDialReason = "own-device" | "group-network-info" | "broadcast-answer" | "configured-server" | "lan-scan" | "websocket-upgrade" | "incoming" | "direct-request" | "group-join";
5
+ /** Bounded path categories used for lifetime counters; attempts also retain the address. */
6
+ export type MeshPath = "websocket" | "webrtc" | "cloud" | "discovery";
7
+ /** Failure categories, independent of free-form transport error messages. */
8
+ export type MeshFailureReason = "ttl0" | "no-route" | "signaling-timeout" | "socket-error" | "socket-timeout" | "handshake" | "rejected" | "closed" | "superseded" | "unsupported" | "sender-not-known" | "trust-refused" | "identity-mismatch" | "cancelled" | "capacity";
9
+ /** Observed stage; timestamps are offsets in milliseconds from the attempt's queued time. */
10
+ export type MeshStage = "queued" | "started" | "authenticated" | "admitted" | "ready" | "firstSync";
11
+ /** Local dial metadata and cancellation; never serialized into device messages. */
12
+ export interface IMeshDial {
13
+ /** Cancels pending transport work; an admitted winner is retained. */
14
+ signal?: AbortSignal;
15
+ /** Scheduler priority: bootstrap, coverage, repair, then redundancy. */
16
+ priority?: 1 | 2 | 3 | 4;
17
+ attemptId?: string;
18
+ reason?: MeshDialReason;
19
+ targetDeviceId?: string;
20
+ /** One-based retry number; absent for the initial dial. */
21
+ retry?: number;
22
+ }
23
+ /** One dial or inbound connection. Missing stages have not been observed. */
24
+ export interface IMeshAttempt {
25
+ attemptId: string;
26
+ targetDeviceId?: string;
27
+ reason: MeshDialReason;
28
+ /** One-based retry number; absent for initial and incoming attempts. */
29
+ retry?: number;
30
+ /** Scheduler priority when this was planned locally. */
31
+ priority?: 1 | 2 | 3 | 4;
32
+ direction: "outgoing" | "incoming";
33
+ path: MeshPath;
34
+ address?: string;
35
+ queuedAt: number;
36
+ stages: Partial<Record<MeshStage, number>>;
37
+ answeredDeviceId?: string;
38
+ expectedIdentity?: boolean;
39
+ answered: boolean;
40
+ lastSignalFailure?: {
41
+ reason: "ttl0" | "no-route";
42
+ detail?: string;
43
+ };
44
+ ready: Record<string, number>;
45
+ firstSync: Record<string, number>;
46
+ outcome: "pending" | "admitted" | "failed" | "cancelled" | "unfinished";
47
+ endReason?: "buffer-evicted" | "disposed";
48
+ endedAt?: number;
49
+ durationMs?: number;
50
+ failure?: {
51
+ stage: MeshStage;
52
+ reason: MeshFailureReason;
53
+ detail?: string;
54
+ };
55
+ doubleDial: boolean;
56
+ offline: boolean;
57
+ outOfOrder: boolean;
58
+ }
59
+ /** Millisecond durations derived from one episode; absent means not observed. */
60
+ export interface IMeshDurations {
61
+ T_first?: number;
62
+ T_own?: number;
63
+ T_cover?: number;
64
+ T_resume?: number;
65
+ repairStart?: number;
66
+ }
67
+ /** Coverage at the latest observation (at completion for a finished episode). */
68
+ export interface IMeshContextCoverage {
69
+ dataContextId: string;
70
+ possibleSourceDeviceIds: string[];
71
+ usableDeviceIds: string[];
72
+ excluded: boolean;
73
+ /** True when an unmet context cannot currently fit at the connection cap. */
74
+ limitedByCapacity?: boolean;
75
+ /** Planner target; zero means no possible source. */
76
+ target?: number;
77
+ }
78
+ /** One connectivity episode, independent of any other episode in flight. */
79
+ export interface IMeshEpisode {
80
+ episodeId: string;
81
+ reason: MeshEpisodeReason;
82
+ trigger?: string;
83
+ startedAt: number;
84
+ endedAt?: number;
85
+ durationMs?: number;
86
+ outcome: "active" | "covered" | "unfinished" | "not-measured";
87
+ endReason?: "covered" | "deadline" | "buffer-evicted" | "disposed" | "page-hidden" | "still-covered";
88
+ metrics: IMeshDurations;
89
+ contexts: IMeshContextCoverage[];
90
+ }
91
+ /** Nearest-rank percentiles of observed values only; count exposes the denominator. */
92
+ export interface IMeshPercentiles {
93
+ count: number;
94
+ p50?: number;
95
+ p90?: number;
96
+ p95?: number;
97
+ p99?: number;
98
+ }
99
+ /** Lifetime dial totals. Incoming connections are separate from the outgoing-dial ratio. */
100
+ export interface IMeshPathCounters {
101
+ dials: number;
102
+ connections: number;
103
+ incomingConnections: number;
104
+ dialsPerConnection: number | null;
105
+ failures: Partial<Record<MeshFailureReason, number>>;
106
+ }
107
+ /** Shared relay totals and current gauges, also exposed on non-Services hosts. */
108
+ export interface IMeshServicesCounters {
109
+ directRelays: number;
110
+ floodsForwarded: number;
111
+ floodsPruned: number;
112
+ pendingEmits: number;
113
+ concurrentConnections: number;
114
+ connects: number;
115
+ disconnects: number;
116
+ }
117
+ /** In-memory diagnostics snapshot. No history survives a runtime restart. */
118
+ export interface IMeshStats {
119
+ startedAt: number;
120
+ sampledAt: number;
121
+ uptimeMs: number;
122
+ readyToDialMs?: number;
123
+ limits: {
124
+ episodes: number;
125
+ attempts: number;
126
+ episodeMs: number;
127
+ };
128
+ currentEpisodes: IMeshEpisode[];
129
+ recentEpisodes: IMeshEpisode[];
130
+ percentiles: Record<keyof IMeshDurations, IMeshPercentiles>;
131
+ counters: {
132
+ paths: Record<MeshPath, IMeshPathCounters>;
133
+ lanScan: {
134
+ scans: number;
135
+ probes: number;
136
+ connected: number;
137
+ };
138
+ /** Lifetime episodes excluded from latency percentiles, by reason. */
139
+ unmeasuredEpisodes?: {
140
+ pageHidden: number;
141
+ stillCovered: number;
142
+ };
143
+ unfinishedAttempts: number;
144
+ doubleDials: number;
145
+ offlineDials: number;
146
+ offlineDialsPerHour: number;
147
+ broadcasts: {
148
+ sent: number;
149
+ answered: number;
150
+ ttl0: number;
151
+ failed: number;
152
+ pending: number;
153
+ perHour: number;
154
+ };
155
+ services: IMeshServicesCounters;
156
+ };
157
+ recentAttempts: IMeshAttempt[];
158
+ recentBroadcasts: IMeshBroadcast[];
159
+ /** Latest planner coverage, including zero targets and capacity limitations. */
160
+ coverage?: IMeshContextCoverage[];
161
+ }
162
+ /** A discovery broadcast and its observed reply, bounded with the attempt history. */
163
+ export interface IMeshBroadcast {
164
+ broadcastId: string;
165
+ dataContextId?: string;
166
+ sentAt: number;
167
+ durationMs?: number;
168
+ outcome: "pending" | "answered" | "ttl0" | "failed";
169
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -4,12 +4,15 @@ import type { Observable } from "../../observable";
4
4
  import type { INetworkInfo } from "../../types/peer-device";
5
5
  import type { IContractConsumerBase } from "../contract-proxy";
6
6
  import type { IContractDefinition } from "../types";
7
+ import type { IMeshStats } from "./mesh-metrics-types";
8
+ export type * from "./mesh-metrics-types";
7
9
  /** Version of the built-in System Network Diagnostics contract. */
8
10
  export declare const NETWORK_DIAGNOSTICS_CONTRACT_VERSION = 1;
9
11
  /** Version of the built-in System Network Control contract. */
10
12
  export declare const NETWORK_CONTROL_CONTRACT_VERSION = 1;
11
13
  /** Stable IDs for tools in System Network Diagnostics v1. */
12
14
  export declare const networkDiagnosticsToolIds: {
15
+ readonly getMeshStats: string;
13
16
  readonly getOverview: "00ms1yb50ym353ads0gel5jpv";
14
17
  readonly getConnections: "00ms1yb50ykny9kdgiclpa1t4";
15
18
  readonly getGroupSyncStatus: "00ms1yb50yp2q7jr0jglzsztq";
@@ -241,6 +244,11 @@ export interface INetworkDiagnosticsConsumer extends IContractConsumerBase {
241
244
  getOverview(): Promise<{
242
245
  overview: INetworkOverview;
243
246
  }>;
247
+ getMeshStats(input?: {
248
+ limit?: number;
249
+ }): Promise<{
250
+ stats: IMeshStats;
251
+ }>;
244
252
  getConnections(): Promise<{
245
253
  connections: INetworkConnectionInfo[];
246
254
  }>;
@@ -6,12 +6,18 @@ exports.getNetworkControlContractDefinition = getNetworkControlContractDefinitio
6
6
  const system_ids_1 = require("../../system-ids");
7
7
  const field_type_1 = require("../../types/field-type");
8
8
  const system_contracts_1 = require("../system-contracts");
9
+ const tool_catalog_identity_1 = require("../tool-catalog-identity");
9
10
  /** Version of the built-in System Network Diagnostics contract. */
10
11
  exports.NETWORK_DIAGNOSTICS_CONTRACT_VERSION = 1;
11
12
  /** Version of the built-in System Network Control contract. */
12
13
  exports.NETWORK_CONTROL_CONTRACT_VERSION = 1;
13
14
  /** Stable IDs for tools in System Network Diagnostics v1. */
14
15
  exports.networkDiagnosticsToolIds = {
16
+ getMeshStats: (0, tool_catalog_identity_1.deriveToolCatalogId)({
17
+ contractId: system_ids_1.networkDiagnosticsContractId,
18
+ version: exports.NETWORK_DIAGNOSTICS_CONTRACT_VERSION,
19
+ toolName: "getMeshStats",
20
+ }),
15
21
  getOverview: "00ms1yb50ym353ads0gel5jpv",
16
22
  getConnections: "00ms1yb50ykny9kdgiclpa1t4",
17
23
  getGroupSyncStatus: "00ms1yb50yp2q7jr0jglzsztq",
@@ -46,6 +52,16 @@ function getNetworkDiagnosticsContractDefinition() {
46
52
  description: "Portable local network, connection, and synchronization diagnostics.",
47
53
  tables: [],
48
54
  tools: [
55
+ {
56
+ name: "getMeshStats",
57
+ usageDescription: "Read bounded in-memory connectivity episodes, attempts, percentiles and relay counters.",
58
+ inputFields: [
59
+ field("limit", field_type_1.FieldType.number, "Maximum recent attempts and broadcasts (default 50, range 0–500). Episodes and counters are always complete.", { optional: true }),
60
+ ],
61
+ outputFields: [
62
+ field("stats", field_type_1.FieldType.object, "Connectivity measurements since runtime startup."),
63
+ ],
64
+ },
49
65
  {
50
66
  name: "getOverview",
51
67
  usageDescription: "Return aggregate network and group information.",
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FilesTable = void 0;
4
4
  exports.Files = Files;
5
5
  const user_context_singleton_1 = require("../../context/user-context-singleton");
6
- const rpc_types_1 = require("../../rpc-types");
7
6
  const orm_1 = require("../orm");
8
7
  const table_definitions_system_1 = require("../orm/table-definitions.system");
9
8
  const chunk_store_1 = require("./chunk-store");
@@ -166,18 +165,3 @@ exports.FilesTable = FilesTable;
166
165
  function Files(dataContext) {
167
166
  return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(file_types_1.filesMetaData, file_types_1.fileSchema);
168
167
  }
169
- // Deprecated RPCs, kept only for Family Hub 0.3.x until its port is Home's version. New code
170
- // uses System Files, which is bound to the caller's own data context.
171
- rpc_types_1.rpcServerCalls.getFileContentsBase64 = async (fileId) => {
172
- const data = await Files().getFileContents(fileId);
173
- if (data === null) {
174
- throw new Error(`File not found: ${fileId}`);
175
- }
176
- return Buffer.from(data).toString("base64");
177
- };
178
- rpc_types_1.rpcServerCalls.saveFile = async (input) => {
179
- const encoding = input.encoding || "utf8";
180
- const dataBuffer = encoding === "base64" ? Buffer.from(input.data, "base64") : Buffer.from(input.data, "utf8");
181
- // Kept: Family Hub 0.3.x doesn't declare its file fields, so nothing would reference these.
182
- return await Files().saveFile({ name: input.name, mimeType: input.mimeType, keep: true }, new Uint8Array(dataBuffer));
183
- };
@@ -21,6 +21,9 @@ export declare class Connection {
21
21
  private _remoteDeviceInfo;
22
22
  /** Trust assigned to the remote identity once the handshake completes. */
23
23
  trustLevel: TrustLevel;
24
+ /** Synchronous diagnostics only; observer errors cannot affect handshake results. */
25
+ onHandshakeObserved?: (stage: "authenticated" | "failed", error?: unknown) => void;
26
+ private observeHandshake;
24
27
  /** Server-side hook fired shortly after the successful handshake reply has been sent. */
25
28
  onHandshakeComplete: ((deviceInfo: IDeviceInfo) => void) | undefined;
26
29
  /** RPC timeout for {@link Connection.emit}. */
@@ -39,6 +42,8 @@ export declare class Connection {
39
42
  private pendingSendArm;
40
43
  /** Bumped by every {@link Connection.reset}, so a handshake can tell it was cut short. */
41
44
  private handshakeGeneration;
45
+ /** Local close intent, retained through reset so retry owners do not penalize orderly shedding. */
46
+ closeIntent?: "remote" | "policy";
42
47
  constructor(socket: ISocket, localDevice: Device, localDeviceServerAddresses?: string[] | undefined, getTrustLevel?: GetTrustLevel);
43
48
  /** True once the remote identity has been authenticated by the handshake. */
44
49
  get verified(): boolean;
@@ -148,5 +153,8 @@ export declare class Connection {
148
153
  */
149
154
  close(): Promise<void>;
150
155
  }
151
- /** Normalizes a peer address for transport and security comparisons. */
156
+ /** Lowercases a peer address and removes a trailing slash; preserves its scheme. */
152
157
  export declare function normalizeAddress(address: string): string;
158
+ /** Local handshake refusal. Its existing Error text remains compatible with older peers. */
159
+ export declare class ConnectionTrustError extends Error {
160
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Connection = void 0;
3
+ exports.ConnectionTrustError = exports.Connection = void 0;
4
4
  exports.normalizeAddress = normalizeAddress;
5
5
  const user_context_singleton_1 = require("../context/user-context-singleton");
6
6
  const data_1 = require("../data");
@@ -32,6 +32,16 @@ class Connection {
32
32
  };
33
33
  /** Trust assigned to the remote identity once the handshake completes. */
34
34
  trustLevel = socket_type_1.TrustLevel.Unknown;
35
+ /** Synchronous diagnostics only; observer errors cannot affect handshake results. */
36
+ onHandshakeObserved;
37
+ observeHandshake(stage, error) {
38
+ try {
39
+ this.onHandshakeObserved?.(stage, error);
40
+ }
41
+ catch {
42
+ /* diagnostics never affect the handshake */
43
+ }
44
+ }
35
45
  /** Server-side hook fired shortly after the successful handshake reply has been sent. */
36
46
  onHandshakeComplete;
37
47
  /** RPC timeout for {@link Connection.emit}. */
@@ -52,6 +62,8 @@ class Connection {
52
62
  pendingSendArm;
53
63
  /** Bumped by every {@link Connection.reset}, so a handshake can tell it was cut short. */
54
64
  handshakeGeneration = 0;
65
+ /** Local close intent, retained through reset so retry owners do not penalize orderly shedding. */
66
+ closeIntent;
55
67
  constructor(socket, localDevice, localDeviceServerAddresses, getTrustLevel = () => Promise.resolve(socket_type_1.TrustLevel.Unknown)) {
56
68
  this.localDevice = localDevice;
57
69
  this.localDeviceServerAddresses = localDeviceServerAddresses;
@@ -66,6 +78,7 @@ class Connection {
66
78
  socket.setPlaintextStreamsAllowed?.(false);
67
79
  // Only the server side of a connection should expose these methods
68
80
  this.exposeRPC("close", () => {
81
+ this.closeIntent ??= "remote";
69
82
  (0, utils_1.sleep)(100).then(() => {
70
83
  this.closeLocal();
71
84
  });
@@ -133,6 +146,7 @@ class Connection {
133
146
  }
134
147
  }
135
148
  catch (e) {
149
+ this.observeHandshake("failed", e);
136
150
  console.error("Error handling completeHandshake", e);
137
151
  callback({ error: e?.message ?? String(e), errorType: "RPC_ERROR" });
138
152
  }
@@ -393,7 +407,7 @@ class Connection {
393
407
  this.assertHandshakeCurrent(generation);
394
408
  if (trustLevel < socket_type_1.TrustLevel.Unknown) {
395
409
  this.resetRemote();
396
- throw new Error("Untrusted connection");
410
+ throw new ConnectionTrustError("Untrusted connection");
397
411
  }
398
412
  // The client seals everything after it reads our response, so receive
399
413
  // can arm now; send arms after the response frame goes out.
@@ -412,6 +426,7 @@ class Connection {
412
426
  };
413
427
  this.trustLevel = trustLevel;
414
428
  this._verified = true;
429
+ this.observeHandshake("authenticated");
415
430
  return handshakeResponse;
416
431
  }
417
432
  /**
@@ -454,11 +469,12 @@ class Connection {
454
469
  this.trustLevel = trustLevel;
455
470
  if (this.trustLevel < socket_type_1.TrustLevel.Unknown) {
456
471
  this.resetRemote();
457
- throw new Error("Untrusted connection");
472
+ throw new ConnectionTrustError("Untrusted connection");
458
473
  }
459
474
  return handshakeResponse;
460
475
  }
461
476
  catch (e) {
477
+ this.observeHandshake("failed", e);
462
478
  // A failed or timed-out attempt must neither retain its ephemeral secret nor let a
463
479
  // late reply authenticate it. Do not clear state belonging to a newer handshake.
464
480
  if (generation === this.handshakeGeneration)
@@ -522,6 +538,7 @@ class Connection {
522
538
  : remoteDeviceInfo.deviceName,
523
539
  };
524
540
  this._verified = true;
541
+ this.observeHandshake("authenticated");
525
542
  this._connectionAddress = remoteAddress;
526
543
  return handshakeResponse;
527
544
  }
@@ -599,7 +616,11 @@ async function noteHandshakeContest(contest) {
599
616
  console.warn("Could not apply a key contest from the handshake", err);
600
617
  }
601
618
  }
602
- /** Normalizes a peer address for transport and security comparisons. */
619
+ /** Lowercases a peer address and removes a trailing slash; preserves its scheme. */
603
620
  function normalizeAddress(address) {
604
621
  return address.toLowerCase().replace(/\/$/, "");
605
622
  }
623
+ /** Local handshake refusal. Its existing Error text remains compatible with older peers. */
624
+ class ConnectionTrustError extends Error {
625
+ }
626
+ exports.ConnectionTrustError = ConnectionTrustError;
@@ -14,6 +14,7 @@ import type { IBinaryPeer } from "./binary-peer-connection-v2";
14
14
  interface ISocketIO {
15
15
  id?: string;
16
16
  on(event: string, handler: (...args: any[]) => void): void;
17
+ off(event: string, handler: (...args: any[]) => void): void;
17
18
  emit(event: string, ...args: any[]): void;
18
19
  removeAllListeners(event?: string): void;
19
20
  disconnect(): void;
@@ -22,8 +22,11 @@ function wrapSocketIOAsBinaryPeer(socket) {
22
22
  const closeHandlers = [];
23
23
  const drainHandlers = [];
24
24
  let pendingBytes = 0;
25
+ let closed = false;
25
26
  // Listen for binary data
26
- socket.on(BINARY_EVENT, (data) => {
27
+ const onData = (data) => {
28
+ if (closed)
29
+ return;
27
30
  // Ensure we have a proper Uint8Array
28
31
  const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
29
32
  dataHandlers.forEach((handler) => {
@@ -34,9 +37,16 @@ function wrapSocketIOAsBinaryPeer(socket) {
34
37
  console.error("[socket-io-binary] Error in data handler:", err);
35
38
  }
36
39
  });
37
- });
40
+ };
38
41
  // Listen for disconnect
39
- socket.on("disconnect", () => {
42
+ const onDisconnect = () => {
43
+ if (closed)
44
+ return;
45
+ closed = true;
46
+ // This adapter belongs to one connection incarnation. A delayed close from it
47
+ // must never disconnect a reconnected Socket.IO socket or remove its listeners.
48
+ socket.off(BINARY_EVENT, onData);
49
+ socket.off("disconnect", onDisconnect);
40
50
  closeHandlers.forEach((handler) => {
41
51
  try {
42
52
  handler();
@@ -45,7 +55,9 @@ function wrapSocketIOAsBinaryPeer(socket) {
45
55
  console.error("[socket-io-binary] Error in close handler:", err);
46
56
  }
47
57
  });
48
- });
58
+ };
59
+ socket.on(BINARY_EVENT, onData);
60
+ socket.on("disconnect", onDisconnect);
49
61
  return {
50
62
  on(event, handler) {
51
63
  if (event === "data") {
@@ -59,6 +71,8 @@ function wrapSocketIOAsBinaryPeer(socket) {
59
71
  }
60
72
  },
61
73
  send(data) {
74
+ if (closed)
75
+ return;
62
76
  const bytes = typeof data === "string"
63
77
  ? Buffer.from(data)
64
78
  : data instanceof Uint8Array
@@ -79,7 +93,9 @@ function wrapSocketIOAsBinaryPeer(socket) {
79
93
  });
80
94
  },
81
95
  destroy() {
82
- socket.removeAllListeners(BINARY_EVENT);
96
+ if (closed)
97
+ return;
98
+ onDisconnect();
83
99
  socket.disconnect();
84
100
  },
85
101
  getBufferedAmount() {
@@ -29,28 +29,6 @@ export interface IRemoteLogsQueryInput {
29
29
  export declare const rpcServerCalls: {
30
30
  encryptData: (value: string, groupId?: string) => Promise<string>;
31
31
  tableMethodCall: (dataContextId: string, tableName: string, methodName: string, ...args: any[]) => Promise<any>;
32
- /**
33
- * @deprecated Use System Files (`SystemFiles`, `readWholeFile`). Kept only for Family Hub
34
- * 0.3.x; deleted once its port is Home's version.
35
- */
36
- getFileContentsBase64: (fileId: string) => Promise<string>;
37
- /**
38
- * @deprecated Use System Files (`SystemFiles`). Kept only for Family Hub 0.3.x; deleted once
39
- * its port is Home's version.
40
- */
41
- saveFile: (input: {
42
- name: string;
43
- mimeType?: string;
44
- data: string;
45
- encoding?: "utf8" | "base64";
46
- fileId?: string;
47
- }) => Promise<{
48
- fileId: string;
49
- name: string;
50
- fileSize: number;
51
- fileHash: string;
52
- mimeType?: string;
53
- }>;
54
32
  deleteLocalDatabase: () => Promise<void>;
55
33
  /** Returns info about the pre-migration data directory, or `null` if already cleaned up. */
56
34
  getOldDataDirInfo: () => Promise<{
package/dist/rpc-types.js CHANGED
@@ -14,16 +14,6 @@ function rpcStub(rpcName) {
14
14
  exports.rpcServerCalls = {
15
15
  encryptData: rpcStub("encryptData"),
16
16
  tableMethodCall: rpcStub("tableMethodCall"),
17
- /**
18
- * @deprecated Use System Files (`SystemFiles`, `readWholeFile`). Kept only for Family Hub
19
- * 0.3.x; deleted once its port is Home's version.
20
- */
21
- getFileContentsBase64: rpcStub("getFileContentsBase64"),
22
- /**
23
- * @deprecated Use System Files (`SystemFiles`). Kept only for Family Hub 0.3.x; deleted once
24
- * its port is Home's version.
25
- */
26
- saveFile: rpcStub("saveFile"),
27
17
  deleteLocalDatabase: rpcStub("deleteLocalDatabase"),
28
18
  /** Returns info about the pre-migration data directory, or `null` if already cleaned up. */
29
19
  getOldDataDirInfo: rpcStub("getOldDataDirInfo"),
@@ -26,7 +26,11 @@ export interface IDeviceMessage<T = any> {
26
26
  deviceMessageId: string;
27
27
  /** Device that originated the message. */
28
28
  fromDeviceId: string;
29
- /** Signed source identity used to bootstrap fresh same-user devices. */
29
+ /**
30
+ * Signed source identity. Lets a receiver accept a device it hasn't met yet when the device
31
+ * belongs to the receiver's own user (personal context) or to a counted member of the
32
+ * message's group.
33
+ */
30
34
  fromDeviceInfo?: ISignedObject<IDeviceInfo>;
31
35
  /** Intended destination device. */
32
36
  toDeviceId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.30.2",
3
+ "version": "0.30.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"