@peers-app/peers-sdk 0.20.6 → 0.21.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.
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.devicePairingStateSchema = exports.devicePairingPhaseSchema = exports.signedPairingInstallationReceiptSchema = exports.pairingInstallationReceiptContentsSchema = exports.pairingCredentialEnvelopeSchema = exports.pairingCredentialContentsSchema = exports.signedPairingApprovalSchema = exports.pairingApprovalContentsSchema = exports.pairingDescriptionSchema = exports.pairingDevicePresentationSchema = exports.devicePairingTranscriptSchema = exports.devicePairingIceServersAckSchema = exports.devicePairingRoomReadyAckSchema = exports.devicePairingSignalingAckSchema = exports.devicePairingSignalingErrorCodeSchema = exports.devicePairingDeleteRoomRequestSchema = exports.devicePairingJoinRoomRequestSchema = exports.devicePairingCreateRoomRequestSchema = exports.pairingSignalSchema = exports.unsignedPairingSignalSchema = exports.pairingIceServerSchema = exports.pairingIceCandidateSchema = exports.pairingSessionDescriptionSchema = exports.devicePairingInvitationSchema = exports.pairingRoleSchema = exports.pairingEndpointNonceSchema = exports.pairingHashSchema = exports.pairingRoomSecretSchema = exports.pairingRoomIdSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const devices_1 = require("../data/devices");
6
+ const zod_types_1 = require("../types/zod-types");
7
+ const constants_1 = require("./constants");
8
+ const base64UrlSchema = zod_1.z.string().regex(/^[A-Za-z0-9_-]+$/);
9
+ /** A random 128-bit pairing-room identifier encoded as unpadded base64url. */
10
+ exports.pairingRoomIdSchema = base64UrlSchema.length(22);
11
+ /** A random 256-bit pairing-room secret encoded as unpadded base64url. */
12
+ exports.pairingRoomSecretSchema = base64UrlSchema.length(43);
13
+ /** A SHA-256 value encoded as unpadded base64url. */
14
+ exports.pairingHashSchema = base64UrlSchema.length(43);
15
+ /** A random 256-bit endpoint nonce encoded as unpadded base64url. */
16
+ exports.pairingEndpointNonceSchema = base64UrlSchema.length(43);
17
+ /** Source and destination roles in a two-party pairing room. */
18
+ exports.pairingRoleSchema = zod_1.z.enum(["source", "destination"]);
19
+ /** Versioned invitation shared out-of-band from the signed-in source. */
20
+ exports.devicePairingInvitationSchema = zod_1.z
21
+ .object({
22
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
23
+ roomId: exports.pairingRoomIdSchema,
24
+ roomSecret: exports.pairingRoomSecretSchema,
25
+ expiresAt: zod_1.z.number().int().positive(),
26
+ serviceOrigin: zod_1.z
27
+ .string()
28
+ .url()
29
+ .max(2048)
30
+ .refine((value) => {
31
+ const url = new URL(value);
32
+ return (url.protocol === "https:" || url.protocol === "http:") && url.origin === value;
33
+ }, "Expected an HTTP(S) origin without a path"),
34
+ })
35
+ .strict();
36
+ /** WebRTC session description carried inside an authenticated signaling message. */
37
+ exports.pairingSessionDescriptionSchema = zod_1.z
38
+ .object({
39
+ type: zod_1.z.enum(["offer", "answer"]),
40
+ sdp: zod_1.z
41
+ .string()
42
+ .min(1)
43
+ .max(64 * 1024),
44
+ endpointNonce: exports.pairingEndpointNonceSchema,
45
+ })
46
+ .strict();
47
+ /** ICE candidate carried inside an authenticated signaling message. */
48
+ exports.pairingIceCandidateSchema = zod_1.z
49
+ .object({
50
+ candidate: zod_1.z.string().min(1).max(4096),
51
+ sdpMid: zod_1.z.string().max(256).nullable().optional(),
52
+ sdpMLineIndex: zod_1.z.number().int().min(0).max(65535).nullable().optional(),
53
+ usernameFragment: zod_1.z.string().max(256).nullable().optional(),
54
+ })
55
+ .strict();
56
+ const iceUrlSchema = zod_1.z
57
+ .string()
58
+ .min(1)
59
+ .max(2048)
60
+ .refine((value) => value.startsWith("stun:") || value.startsWith("turn:") || value.startsWith("turns:"), "Expected a STUN or TURN URL");
61
+ /** Validated ICE server configuration issued to a pairing-room member. */
62
+ exports.pairingIceServerSchema = zod_1.z
63
+ .object({
64
+ urls: zod_1.z.union([iceUrlSchema, zod_1.z.array(iceUrlSchema).min(1).max(16)]),
65
+ username: zod_1.z.string().min(1).max(256).optional(),
66
+ credential: zod_1.z.string().min(1).max(512).optional(),
67
+ })
68
+ .strict()
69
+ .refine((value) => (value.username === undefined && value.credential === undefined) ||
70
+ (value.username !== undefined && value.credential !== undefined), "TURN username and credential must be supplied together");
71
+ const pairingSignalBase = {
72
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
73
+ roomId: exports.pairingRoomIdSchema,
74
+ senderRole: exports.pairingRoleSchema,
75
+ sequence: zod_1.z.number().int().positive(),
76
+ };
77
+ /** Unsigned offer, answer, or ICE message before its signaling MAC is attached. */
78
+ exports.unsignedPairingSignalSchema = zod_1.z.discriminatedUnion("kind", [
79
+ zod_1.z
80
+ .object({
81
+ ...pairingSignalBase,
82
+ kind: zod_1.z.literal("offer"),
83
+ payload: exports.pairingSessionDescriptionSchema.extend({ type: zod_1.z.literal("offer") }).strict(),
84
+ })
85
+ .strict(),
86
+ zod_1.z
87
+ .object({
88
+ ...pairingSignalBase,
89
+ kind: zod_1.z.literal("answer"),
90
+ payload: exports.pairingSessionDescriptionSchema.extend({ type: zod_1.z.literal("answer") }).strict(),
91
+ })
92
+ .strict(),
93
+ zod_1.z
94
+ .object({
95
+ ...pairingSignalBase,
96
+ kind: zod_1.z.literal("candidate"),
97
+ payload: exports.pairingIceCandidateSchema,
98
+ })
99
+ .strict(),
100
+ ]);
101
+ /** HMAC-authenticated offer, answer, or ICE signaling message. */
102
+ exports.pairingSignalSchema = zod_1.z.discriminatedUnion("kind", [
103
+ zod_1.z
104
+ .object({
105
+ ...pairingSignalBase,
106
+ kind: zod_1.z.literal("offer"),
107
+ payload: exports.pairingSessionDescriptionSchema.extend({ type: zod_1.z.literal("offer") }).strict(),
108
+ mac: exports.pairingHashSchema,
109
+ })
110
+ .strict(),
111
+ zod_1.z
112
+ .object({
113
+ ...pairingSignalBase,
114
+ kind: zod_1.z.literal("answer"),
115
+ payload: exports.pairingSessionDescriptionSchema.extend({ type: zod_1.z.literal("answer") }).strict(),
116
+ mac: exports.pairingHashSchema,
117
+ })
118
+ .strict(),
119
+ zod_1.z
120
+ .object({
121
+ ...pairingSignalBase,
122
+ kind: zod_1.z.literal("candidate"),
123
+ payload: exports.pairingIceCandidateSchema,
124
+ mac: exports.pairingHashSchema,
125
+ })
126
+ .strict(),
127
+ ]);
128
+ /** Request from the source to create a bounded signaling room. */
129
+ exports.devicePairingCreateRoomRequestSchema = zod_1.z
130
+ .object({
131
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
132
+ roomId: exports.pairingRoomIdSchema,
133
+ expiresAt: zod_1.z.number().int().positive(),
134
+ roomAccessTokenHash: exports.pairingHashSchema,
135
+ })
136
+ .strict();
137
+ /** Request from the destination to occupy the second room slot. */
138
+ exports.devicePairingJoinRoomRequestSchema = zod_1.z
139
+ .object({
140
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
141
+ roomId: exports.pairingRoomIdSchema,
142
+ roomAccessToken: exports.pairingHashSchema,
143
+ })
144
+ .strict();
145
+ /** Request from the source to tear down its signaling room. */
146
+ exports.devicePairingDeleteRoomRequestSchema = zod_1.z
147
+ .object({
148
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
149
+ roomId: exports.pairingRoomIdSchema,
150
+ roomAccessToken: exports.pairingHashSchema,
151
+ })
152
+ .strict();
153
+ /** Public signaling-service error codes that do not echo attacker input. */
154
+ exports.devicePairingSignalingErrorCodeSchema = zod_1.z.enum([
155
+ "invalid",
156
+ "not-found",
157
+ "occupied",
158
+ "expired",
159
+ "forbidden",
160
+ "rate-limited",
161
+ "too-large",
162
+ "out-of-order",
163
+ ]);
164
+ const devicePairingSignalingFailureSchema = zod_1.z
165
+ .object({
166
+ ok: zod_1.z.literal(false),
167
+ code: exports.devicePairingSignalingErrorCodeSchema,
168
+ })
169
+ .strict();
170
+ /** Acknowledgement returned by every signaling-room command. */
171
+ exports.devicePairingSignalingAckSchema = zod_1.z.discriminatedUnion("ok", [
172
+ zod_1.z.object({ ok: zod_1.z.literal(true) }).strict(),
173
+ devicePairingSignalingFailureSchema,
174
+ ]);
175
+ /** Acknowledgement proving room creation/join and its service-authoritative expiry. */
176
+ exports.devicePairingRoomReadyAckSchema = zod_1.z.discriminatedUnion("ok", [
177
+ zod_1.z
178
+ .object({
179
+ ok: zod_1.z.literal(true),
180
+ expiresAt: zod_1.z.number().int().positive(),
181
+ })
182
+ .strict(),
183
+ devicePairingSignalingFailureSchema,
184
+ ]);
185
+ /** Acknowledgement containing room-bound, short-lived ICE configuration. */
186
+ exports.devicePairingIceServersAckSchema = zod_1.z.discriminatedUnion("ok", [
187
+ zod_1.z
188
+ .object({
189
+ ok: zod_1.z.literal(true),
190
+ iceServers: zod_1.z.array(exports.pairingIceServerSchema).min(1).max(8),
191
+ })
192
+ .strict(),
193
+ devicePairingSignalingFailureSchema,
194
+ ]);
195
+ /** Canonical transcript input derived independently by both endpoints. */
196
+ exports.devicePairingTranscriptSchema = zod_1.z
197
+ .object({
198
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
199
+ roomId: exports.pairingRoomIdSchema,
200
+ sourceIdentity: devices_1.deviceInfoSchema,
201
+ destinationIdentity: devices_1.deviceInfoSchema,
202
+ sourceEndpointNonce: exports.pairingEndpointNonceSchema,
203
+ destinationEndpointNonce: exports.pairingEndpointNonceSchema,
204
+ offerFingerprint: zod_1.z.string().min(1).max(256),
205
+ answerFingerprint: zod_1.z.string().min(1).max(256),
206
+ })
207
+ .strict();
208
+ /** Renderer-safe presentation of the remote endpoint. */
209
+ exports.pairingDevicePresentationSchema = zod_1.z
210
+ .object({
211
+ deviceName: devices_1.displayNameSchema.optional(),
212
+ userName: devices_1.displayNameSchema.optional(),
213
+ deviceType: zod_1.z.string().max(64).optional(),
214
+ })
215
+ .strict();
216
+ /** Payload exchanged by `pairing.describe` after the normal Connection handshake. */
217
+ exports.pairingDescriptionSchema = zod_1.z
218
+ .object({
219
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
220
+ transcriptHash: exports.pairingHashSchema,
221
+ device: devices_1.deviceInfoSchema,
222
+ presentation: exports.pairingDevicePresentationSchema,
223
+ })
224
+ .strict();
225
+ /** Contents of a signed, single-use user approval. */
226
+ exports.pairingApprovalContentsSchema = zod_1.z
227
+ .object({
228
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
229
+ approvalId: exports.pairingEndpointNonceSchema,
230
+ transcriptHash: exports.pairingHashSchema,
231
+ role: exports.pairingRoleSchema,
232
+ expiresAt: zod_1.z.number().int().positive(),
233
+ })
234
+ .strict();
235
+ /** Signed approval bound to one transcript and endpoint identity. */
236
+ exports.signedPairingApprovalSchema = zod_1.z
237
+ .object({
238
+ contents: exports.pairingApprovalContentsSchema,
239
+ signature: base64UrlSchema.length(86),
240
+ publicKey: base64UrlSchema.length(43),
241
+ })
242
+ .strict();
243
+ /** Account credentials encrypted directly to the temporary destination identity. */
244
+ exports.pairingCredentialContentsSchema = zod_1.z
245
+ .object({
246
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
247
+ transcriptHash: exports.pairingHashSchema,
248
+ expiresAt: zod_1.z.number().int().positive(),
249
+ userId: zod_types_1.zodPeerId,
250
+ secretKey: base64UrlSchema.length(86),
251
+ })
252
+ .strict();
253
+ /** Signed-and-boxed credential envelope sent over the WebRTC Connection. */
254
+ exports.pairingCredentialEnvelopeSchema = zod_1.z
255
+ .object({
256
+ contents: base64UrlSchema.min(1).max(4096),
257
+ nonce: base64UrlSchema.length(32),
258
+ fromPublicKey: base64UrlSchema.length(43),
259
+ })
260
+ .strict();
261
+ /** Contents of the temporary destination identity's signed installation receipt. */
262
+ exports.pairingInstallationReceiptContentsSchema = zod_1.z
263
+ .object({
264
+ version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
265
+ transcriptHash: exports.pairingHashSchema,
266
+ initializedDevice: devices_1.deviceInfoSchema,
267
+ installedAt: zod_1.z.number().int().positive(),
268
+ })
269
+ .strict();
270
+ /** Receipt proving installation on the authenticated temporary destination endpoint. */
271
+ exports.signedPairingInstallationReceiptSchema = zod_1.z
272
+ .object({
273
+ contents: exports.pairingInstallationReceiptContentsSchema,
274
+ signature: base64UrlSchema.length(86),
275
+ publicKey: base64UrlSchema.length(43),
276
+ })
277
+ .strict();
278
+ /** Renderer-visible phases of the short-lived pairing ceremony. */
279
+ exports.devicePairingPhaseSchema = zod_1.z.enum([
280
+ "idle",
281
+ "inviting",
282
+ "connecting",
283
+ "comparing",
284
+ "waiting-for-approval",
285
+ "transferring",
286
+ "complete",
287
+ "rejected",
288
+ "error",
289
+ ]);
290
+ /** Sanitized pairing state safe to publish across the host/renderer boundary. */
291
+ exports.devicePairingStateSchema = zod_1.z
292
+ .object({
293
+ sessionId: zod_types_1.zodPeerId.optional(),
294
+ role: exports.pairingRoleSchema.optional(),
295
+ phase: exports.devicePairingPhaseSchema,
296
+ expiresAt: zod_1.z.number().int().positive().optional(),
297
+ remoteDevice: exports.pairingDevicePresentationSchema.optional(),
298
+ sas: zod_1.z
299
+ .string()
300
+ .regex(/^\d{6}$/)
301
+ .optional(),
302
+ error: zod_1.z.string().max(256).optional(),
303
+ })
304
+ .strict();
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export * from "./device/get-trust-level-fn";
13
13
  export * from "./device/socket.type";
14
14
  export * from "./device/socket-io-binary-peer";
15
15
  export * from "./device/tx-encoding";
16
+ export * from "./device-pairing";
16
17
  export * from "./events";
17
18
  export * from "./group-invite";
18
19
  export * from "./keys";
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __exportStar(require("./device/get-trust-level-fn"), exports);
34
34
  __exportStar(require("./device/socket.type"), exports);
35
35
  __exportStar(require("./device/socket-io-binary-peer"), exports);
36
36
  __exportStar(require("./device/tx-encoding"), exports);
37
+ __exportStar(require("./device-pairing"), exports);
37
38
  __exportStar(require("./events"), exports);
38
39
  __exportStar(require("./group-invite"), exports);
39
40
  __exportStar(require("./keys"), exports);
@@ -1,5 +1,6 @@
1
1
  import type { IDeviceDatabaseQueryResult, IDeviceOperationStatus, IDeviceToolRunInput } from "./contracts/system/device-operations-contract";
2
2
  import type { ITool } from "./data/tools";
3
+ import type { DevicePairingCeremonyAction, DevicePairingStartDestinationInput, DevicePairingStartSourceResult, DevicePairingState } from "./device-pairing";
3
4
  import type { IConsoleLog } from "./logging/console-logs.table";
4
5
  /** Named event payload sent across the frontend RPC bridge. */
5
6
  export interface IEventData<T = any> {
@@ -63,6 +64,13 @@ export declare const rpcServerCalls: {
63
64
  seedBundledPeersCore: (dataContextId?: string) => Promise<boolean>;
64
65
  setUserIdAndSecretKey: (userId: string, secretKey: string) => Promise<void>;
65
66
  getUserId: () => Promise<string | undefined>;
67
+ devicePairingStartSource: () => Promise<DevicePairingStartSourceResult>;
68
+ devicePairingStartDestination: (input: DevicePairingStartDestinationInput) => Promise<DevicePairingState>;
69
+ devicePairingApprove: (input: DevicePairingCeremonyAction) => Promise<DevicePairingState>;
70
+ devicePairingReject: (input: DevicePairingCeremonyAction) => Promise<DevicePairingState>;
71
+ devicePairingCancel: (input: DevicePairingCeremonyAction) => Promise<DevicePairingState>;
72
+ devicePairingGetState: () => Promise<DevicePairingState>;
73
+ devicePairingGetInvitationUrl: () => Promise<string | undefined>;
66
74
  encryptData: (value: string, groupId?: string) => Promise<string>;
67
75
  /**
68
76
  * Decrypt (if secret) and copy a persistent variable's value to the system clipboard
package/dist/rpc-types.js CHANGED
@@ -21,6 +21,13 @@ exports.rpcServerCalls = {
21
21
  seedBundledPeersCore: rpcStub("seedBundledPeersCore"),
22
22
  setUserIdAndSecretKey: rpcStub("setUserIdAndSecretKey"),
23
23
  getUserId: rpcStub("getUserId"),
24
+ devicePairingStartSource: rpcStub("devicePairingStartSource"),
25
+ devicePairingStartDestination: rpcStub("devicePairingStartDestination"),
26
+ devicePairingApprove: rpcStub("devicePairingApprove"),
27
+ devicePairingReject: rpcStub("devicePairingReject"),
28
+ devicePairingCancel: rpcStub("devicePairingCancel"),
29
+ devicePairingGetState: rpcStub("devicePairingGetState"),
30
+ devicePairingGetInvitationUrl: rpcStub("devicePairingGetInvitationUrl"),
24
31
  encryptData: rpcStub("encryptData"),
25
32
  /**
26
33
  * Decrypt (if secret) and copy a persistent variable's value to the system clipboard
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.20.6",
3
+ "version": "0.21.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"