@peers-app/peers-sdk 0.23.13 → 0.24.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.
Files changed (82) hide show
  1. package/dist/contracts/index.d.ts +1 -0
  2. package/dist/contracts/index.js +4 -1
  3. package/dist/contracts/system/index.d.ts +2 -0
  4. package/dist/contracts/system/index.js +5 -1
  5. package/dist/contracts/system/invites-contract.d.ts +121 -0
  6. package/dist/contracts/system/invites-contract.js +150 -0
  7. package/dist/data/create-group.d.ts +24 -0
  8. package/dist/data/create-group.js +61 -0
  9. package/dist/data/group-secret.d.ts +10 -0
  10. package/dist/data/group-secret.js +26 -0
  11. package/dist/data/group-share.d.ts +0 -20
  12. package/dist/data/group-share.js +0 -35
  13. package/dist/data/index.d.ts +2 -0
  14. package/dist/data/index.js +2 -0
  15. package/dist/data/invites.d.ts +350 -0
  16. package/dist/data/invites.js +99 -0
  17. package/dist/data/users.js +4 -0
  18. package/dist/device-pairing/constants.d.ts +27 -9
  19. package/dist/device-pairing/constants.js +28 -10
  20. package/dist/device-pairing/cpace.d.ts +46 -0
  21. package/dist/device-pairing/cpace.js +173 -0
  22. package/dist/device-pairing/cpace.test.js +116 -0
  23. package/dist/device-pairing/crypto.d.ts +40 -15
  24. package/dist/device-pairing/crypto.js +74 -33
  25. package/dist/device-pairing/device-pairing.test.js +156 -119
  26. package/dist/device-pairing/index.d.ts +3 -1
  27. package/dist/device-pairing/index.js +3 -1
  28. package/dist/device-pairing/pairing-code.d.ts +27 -0
  29. package/dist/device-pairing/pairing-code.js +84 -0
  30. package/dist/device-pairing/pgp-word-list.d.ts +14 -0
  31. package/dist/device-pairing/pgp-word-list.js +531 -0
  32. package/dist/device-pairing/signaling.d.ts +17 -6
  33. package/dist/device-pairing/signaling.js +31 -8
  34. package/dist/device-pairing/transcript.d.ts +3 -3
  35. package/dist/device-pairing/transcript.js +6 -13
  36. package/dist/device-pairing/types.d.ts +870 -224
  37. package/dist/device-pairing/types.js +186 -108
  38. package/dist/index.d.ts +1 -2
  39. package/dist/index.js +1 -2
  40. package/dist/invites/data-box-schema.d.ts +15 -0
  41. package/dist/invites/data-box-schema.js +15 -0
  42. package/dist/invites/group-approval.d.ts +43 -0
  43. package/dist/invites/group-approval.js +155 -0
  44. package/dist/invites/group-approval.test.js +221 -0
  45. package/dist/invites/index.d.ts +5 -0
  46. package/dist/{group-invite → invites}/index.js +5 -3
  47. package/dist/invites/invite-epoch.d.ts +18 -0
  48. package/dist/invites/invite-epoch.js +35 -0
  49. package/dist/invites/invite-messages.d.ts +1354 -0
  50. package/dist/invites/invite-messages.js +145 -0
  51. package/dist/invites/invite-token.d.ts +334 -0
  52. package/dist/invites/invite-token.js +178 -0
  53. package/dist/invites/invite-token.test.d.ts +1 -0
  54. package/dist/invites/invite-token.test.js +123 -0
  55. package/dist/rpc-types.d.ts +5 -4
  56. package/dist/rpc-types.js +2 -1
  57. package/dist/system-ids.d.ts +22 -0
  58. package/dist/system-ids.js +23 -1
  59. package/dist/types/peer-device.d.ts +15 -1
  60. package/dist/types/peer-device.js +15 -1
  61. package/package.json +1 -1
  62. package/dist/device-pairing/invitation.d.ts +0 -13
  63. package/dist/device-pairing/invitation.js +0 -85
  64. package/dist/group-invite/group-invite.d.ts +0 -53
  65. package/dist/group-invite/group-invite.js +0 -231
  66. package/dist/group-invite/group-invite.pvars.d.ts +0 -94
  67. package/dist/group-invite/group-invite.pvars.js +0 -139
  68. package/dist/group-invite/group-invite.types.d.ts +0 -124
  69. package/dist/group-invite/group-invite.types.js +0 -8
  70. package/dist/group-invite/index.d.ts +0 -3
  71. package/dist/user-connect/connection-code.d.ts +0 -67
  72. package/dist/user-connect/connection-code.js +0 -176
  73. package/dist/user-connect/connection-code.test.js +0 -213
  74. package/dist/user-connect/index.d.ts +0 -3
  75. package/dist/user-connect/index.js +0 -19
  76. package/dist/user-connect/user-connect.pvars.d.ts +0 -20
  77. package/dist/user-connect/user-connect.pvars.js +0 -63
  78. package/dist/user-connect/user-connect.pvars.test.js +0 -46
  79. package/dist/user-connect/user-connect.types.d.ts +0 -94
  80. package/dist/user-connect/user-connect.types.js +0 -68
  81. /package/dist/{user-connect/connection-code.test.d.ts → device-pairing/cpace.test.d.ts} +0 -0
  82. /package/dist/{user-connect/user-connect.pvars.test.d.ts → invites/group-approval.test.d.ts} +0 -0
@@ -1,36 +1,37 @@
1
1
  "use strict";
2
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;
3
+ exports.devicePairingStateSchema = exports.devicePairingPhaseSchema = exports.signedPairingInstallationReceiptSchema = exports.pairingInstallationReceiptContentsSchema = exports.pairingCredentialEnvelopeSchema = exports.pairingCredentialContentsSchema = exports.pairingConfirmationSchema = exports.pairingConfirmationContentsSchema = exports.pairingDevicePresentationSchema = exports.devicePairingTranscriptSchema = exports.devicePairingIceServersAckSchema = exports.devicePairingRoomReadyAckSchema = exports.devicePairingRoomCreatedAckSchema = exports.devicePairingSignalingAckSchema = exports.devicePairingSignalingErrorCodeSchema = exports.devicePairingDeleteRoomRequestSchema = exports.devicePairingJoinRoomRequestSchema = exports.devicePairingCreateRoomRequestSchema = exports.pairingSignalSchema = exports.authenticatedPairingSignalSchema = exports.unsignedPairingSignalSchema = exports.pairingPakeSignalSchema = exports.pairingIceServerSchema = exports.pairingIceCandidateSchema = exports.pairingTransportChoiceSchema = exports.pairingTransportOptionsSchema = exports.pairingWebSocketUrlSchema = exports.pairingTransportSchema = exports.pairingSessionDescriptionSchema = exports.pairingRendezvousSchema = exports.pairingServiceOriginSchema = exports.pairingRoleSchema = exports.pairingNameplateSchema = exports.pairingPakeShareSchema = exports.pairingEndpointNonceSchema = exports.pairingHashSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const devices_1 = require("../data/devices");
6
6
  const zod_types_1 = require("../types/zod-types");
7
7
  const constants_1 = require("./constants");
8
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. */
9
+ /** A SHA-256 value or 256-bit key encoded as unpadded base64url. */
14
10
  exports.pairingHashSchema = base64UrlSchema.length(43);
15
11
  /** A random 256-bit endpoint nonce encoded as unpadded base64url. */
16
12
  exports.pairingEndpointNonceSchema = base64UrlSchema.length(43);
13
+ /** A 32-byte X25519 PAKE public share encoded as unpadded base64url. */
14
+ exports.pairingPakeShareSchema = base64UrlSchema.length(43);
15
+ /** Small integer that names a signaling room; the first element of a pairing code. */
16
+ exports.pairingNameplateSchema = zod_1.z.number().int().min(1).max(constants_1.DEVICE_PAIRING_MAX_NAMEPLATE);
17
17
  /** Source and destination roles in a two-party pairing room. */
18
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
19
+ /** HTTP(S) origin of the signaling service without a path. */
20
+ exports.pairingServiceOriginSchema = zod_1.z
21
+ .string()
22
+ .url()
23
+ .max(2048)
24
+ .refine((value) => {
25
+ const url = new URL(value);
26
+ return (url.protocol === "https:" || url.protocol === "http:") && url.origin === value;
27
+ }, "Expected an HTTP(S) origin without a path");
28
+ /** Established rendezvous shared by both endpoints once the room exists. */
29
+ exports.pairingRendezvousSchema = zod_1.z
21
30
  .object({
22
31
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
23
- roomId: exports.pairingRoomIdSchema,
24
- roomSecret: exports.pairingRoomSecretSchema,
32
+ serviceOrigin: exports.pairingServiceOriginSchema,
33
+ nameplate: exports.pairingNameplateSchema,
25
34
  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
  })
35
36
  .strict();
36
37
  /** WebRTC session description carried inside an authenticated signaling message. */
@@ -41,9 +42,56 @@ exports.pairingSessionDescriptionSchema = zod_1.z
41
42
  .string()
42
43
  .min(1)
43
44
  .max(64 * 1024),
45
+ })
46
+ .strict();
47
+ /** Data transports a pairing ceremony can negotiate after the PAKE. */
48
+ exports.pairingTransportSchema = zod_1.z.enum(["wrtc", "ws"]);
49
+ /** Socket.IO URL a destination hosts for the direct WebSocket transport. */
50
+ exports.pairingWebSocketUrlSchema = zod_1.z
51
+ .string()
52
+ .min(1)
53
+ .max(2048)
54
+ .refine((value) => {
55
+ try {
56
+ const url = new URL(value);
57
+ return ["http:", "https:", "ws:", "wss:"].includes(url.protocol) && url.hostname.length > 0;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }, "Expected an http(s) or ws(s) URL");
63
+ /**
64
+ * Destination's transport options, sent right after both PAKE shares. `websocket.urls` are the
65
+ * Socket.IO origins the destination is listening on for a source that can reach them directly.
66
+ */
67
+ exports.pairingTransportOptionsSchema = zod_1.z
68
+ .object({
44
69
  endpointNonce: exports.pairingEndpointNonceSchema,
70
+ webrtc: zod_1.z.boolean(),
71
+ websocket: zod_1.z
72
+ .object({
73
+ urls: zod_1.z.array(exports.pairingWebSocketUrlSchema).min(1).max(constants_1.DEVICE_PAIRING_MAX_WEBSOCKET_URLS),
74
+ })
75
+ .strict()
76
+ .optional(),
45
77
  })
46
78
  .strict();
79
+ /** Source's transport choice; `url` is the destination URL it connected to for `ws`. */
80
+ exports.pairingTransportChoiceSchema = zod_1.z.discriminatedUnion("selected", [
81
+ zod_1.z
82
+ .object({
83
+ endpointNonce: exports.pairingEndpointNonceSchema,
84
+ selected: zod_1.z.literal("wrtc"),
85
+ })
86
+ .strict(),
87
+ zod_1.z
88
+ .object({
89
+ endpointNonce: exports.pairingEndpointNonceSchema,
90
+ selected: zod_1.z.literal("ws"),
91
+ url: exports.pairingWebSocketUrlSchema,
92
+ })
93
+ .strict(),
94
+ ]);
47
95
  /** ICE candidate carried inside an authenticated signaling message. */
48
96
  exports.pairingIceCandidateSchema = zod_1.z
49
97
  .object({
@@ -70,84 +118,99 @@ exports.pairingIceServerSchema = zod_1.z
70
118
  (value.username !== undefined && value.credential !== undefined), "TURN username and credential must be supplied together");
71
119
  const pairingSignalBase = {
72
120
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
73
- roomId: exports.pairingRoomIdSchema,
121
+ nameplate: exports.pairingNameplateSchema,
74
122
  senderRole: exports.pairingRoleSchema,
75
123
  sequence: zod_1.z.number().int().positive(),
76
124
  };
77
- /** Unsigned offer, answer, or ICE message before its signaling MAC is attached. */
125
+ /** PAKE share exchanged before any key exists; it is not MACed and carries no secrets. */
126
+ exports.pairingPakeSignalSchema = zod_1.z
127
+ .object({
128
+ ...pairingSignalBase,
129
+ kind: zod_1.z.literal("pake"),
130
+ payload: zod_1.z.object({ share: exports.pairingPakeShareSchema }).strict(),
131
+ })
132
+ .strict();
133
+ const unsignedTransportOptionsSignal = zod_1.z
134
+ .object({
135
+ ...pairingSignalBase,
136
+ kind: zod_1.z.literal("transport-options"),
137
+ payload: exports.pairingTransportOptionsSchema,
138
+ })
139
+ .strict();
140
+ const unsignedTransportChoiceSignal = zod_1.z
141
+ .object({
142
+ ...pairingSignalBase,
143
+ kind: zod_1.z.literal("transport-choice"),
144
+ payload: exports.pairingTransportChoiceSchema,
145
+ })
146
+ .strict();
147
+ const unsignedOfferSignal = zod_1.z
148
+ .object({
149
+ ...pairingSignalBase,
150
+ kind: zod_1.z.literal("offer"),
151
+ payload: exports.pairingSessionDescriptionSchema.extend({ type: zod_1.z.literal("offer") }).strict(),
152
+ })
153
+ .strict();
154
+ const unsignedAnswerSignal = zod_1.z
155
+ .object({
156
+ ...pairingSignalBase,
157
+ kind: zod_1.z.literal("answer"),
158
+ payload: exports.pairingSessionDescriptionSchema.extend({ type: zod_1.z.literal("answer") }).strict(),
159
+ })
160
+ .strict();
161
+ const unsignedCandidateSignal = zod_1.z
162
+ .object({
163
+ ...pairingSignalBase,
164
+ kind: zod_1.z.literal("candidate"),
165
+ payload: exports.pairingIceCandidateSchema,
166
+ })
167
+ .strict();
168
+ /**
169
+ * Unsigned transport, offer, answer, or ICE message before its signaling MAC is attached.
170
+ *
171
+ * Order after both PAKE shares: destination `transport-options`, source `transport-choice`, then
172
+ * (WebRTC only) source `offer`, destination `answer`, and `candidate`s from either role.
173
+ */
78
174
  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(),
175
+ unsignedTransportOptionsSignal,
176
+ unsignedTransportChoiceSignal,
177
+ unsignedOfferSignal,
178
+ unsignedAnswerSignal,
179
+ unsignedCandidateSignal,
100
180
  ]);
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(),
181
+ const macField = { mac: exports.pairingHashSchema };
182
+ /** HMAC-authenticated transport, offer, answer, or ICE signaling message. */
183
+ exports.authenticatedPairingSignalSchema = zod_1.z.discriminatedUnion("kind", [
184
+ unsignedTransportOptionsSignal.extend(macField).strict(),
185
+ unsignedTransportChoiceSignal.extend(macField).strict(),
186
+ unsignedOfferSignal.extend(macField).strict(),
187
+ unsignedAnswerSignal.extend(macField).strict(),
188
+ unsignedCandidateSignal.extend(macField).strict(),
189
+ ]);
190
+ /** Any signaling message relayed by peers-services: the PAKE share or an authenticated signal. */
191
+ exports.pairingSignalSchema = zod_1.z.union([
192
+ exports.pairingPakeSignalSchema,
193
+ exports.authenticatedPairingSignalSchema,
127
194
  ]);
128
- /** Request from the source to create a bounded signaling room. */
195
+ /** Request from the destination to create a bounded signaling room and receive a nameplate. */
129
196
  exports.devicePairingCreateRoomRequestSchema = zod_1.z
130
197
  .object({
131
198
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
132
- roomId: exports.pairingRoomIdSchema,
133
199
  expiresAt: zod_1.z.number().int().positive(),
134
- roomAccessTokenHash: exports.pairingHashSchema,
135
200
  })
136
201
  .strict();
137
- /** Request from the destination to occupy the second room slot. */
202
+ /** Request from the source to occupy the room named by the typed or scanned nameplate. */
138
203
  exports.devicePairingJoinRoomRequestSchema = zod_1.z
139
204
  .object({
140
205
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
141
- roomId: exports.pairingRoomIdSchema,
142
- roomAccessToken: exports.pairingHashSchema,
206
+ nameplate: exports.pairingNameplateSchema,
143
207
  })
144
208
  .strict();
145
- /** Request from the source to tear down its signaling room. */
209
+ /** Request from the creating destination socket to tear down its signaling room. */
146
210
  exports.devicePairingDeleteRoomRequestSchema = zod_1.z
147
211
  .object({
148
212
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
149
- roomId: exports.pairingRoomIdSchema,
150
- roomAccessToken: exports.pairingHashSchema,
213
+ nameplate: exports.pairingNameplateSchema,
151
214
  })
152
215
  .strict();
153
216
  /** Public signaling-service error codes that do not echo attacker input. */
@@ -172,7 +235,18 @@ exports.devicePairingSignalingAckSchema = zod_1.z.discriminatedUnion("ok", [
172
235
  zod_1.z.object({ ok: zod_1.z.literal(true) }).strict(),
173
236
  devicePairingSignalingFailureSchema,
174
237
  ]);
175
- /** Acknowledgement proving room creation/join and its service-authoritative expiry. */
238
+ /** Acknowledgement returned to the destination with its allocated nameplate and expiry. */
239
+ exports.devicePairingRoomCreatedAckSchema = zod_1.z.discriminatedUnion("ok", [
240
+ zod_1.z
241
+ .object({
242
+ ok: zod_1.z.literal(true),
243
+ nameplate: exports.pairingNameplateSchema,
244
+ expiresAt: zod_1.z.number().int().positive(),
245
+ })
246
+ .strict(),
247
+ devicePairingSignalingFailureSchema,
248
+ ]);
249
+ /** Acknowledgement proving a room join and its service-authoritative expiry. */
176
250
  exports.devicePairingRoomReadyAckSchema = zod_1.z.discriminatedUnion("ok", [
177
251
  zod_1.z
178
252
  .object({
@@ -192,17 +266,24 @@ exports.devicePairingIceServersAckSchema = zod_1.z.discriminatedUnion("ok", [
192
266
  .strict(),
193
267
  devicePairingSignalingFailureSchema,
194
268
  ]);
195
- /** Canonical transcript input derived independently by both endpoints. */
269
+ /**
270
+ * Canonical transcript input derived independently by both endpoints.
271
+ *
272
+ * `transportBinding` pins the negotiated data channel: for `wrtc` it is the sorted SHA-256 DTLS
273
+ * fingerprints of the offer and answer (`offer|answer`); for `ws` it is the destination URL the
274
+ * source connected to, exactly as advertised in the MACed transport options.
275
+ */
196
276
  exports.devicePairingTranscriptSchema = zod_1.z
197
277
  .object({
198
278
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
199
- roomId: exports.pairingRoomIdSchema,
279
+ serviceOrigin: exports.pairingServiceOriginSchema,
280
+ nameplate: exports.pairingNameplateSchema,
200
281
  sourceIdentity: devices_1.deviceInfoSchema,
201
282
  destinationIdentity: devices_1.deviceInfoSchema,
202
283
  sourceEndpointNonce: exports.pairingEndpointNonceSchema,
203
284
  destinationEndpointNonce: exports.pairingEndpointNonceSchema,
204
- offerFingerprint: zod_1.z.string().min(1).max(256),
205
- answerFingerprint: zod_1.z.string().min(1).max(256),
285
+ transport: exports.pairingTransportSchema,
286
+ transportBinding: zod_1.z.string().min(1).max(4096),
206
287
  })
207
288
  .strict();
208
289
  /** Renderer-safe presentation of the remote endpoint. */
@@ -213,32 +294,22 @@ exports.pairingDevicePresentationSchema = zod_1.z
213
294
  deviceType: zod_1.z.string().max(64).optional(),
214
295
  })
215
296
  .strict();
216
- /** Payload exchanged by `pairing.describe` after the normal Connection handshake. */
217
- exports.pairingDescriptionSchema = zod_1.z
297
+ /** Unauthenticated contents of a `pairing.confirm` message. */
298
+ exports.pairingConfirmationContentsSchema = zod_1.z
218
299
  .object({
219
300
  version: zod_1.z.literal(constants_1.DEVICE_PAIRING_PROTOCOL_VERSION),
301
+ role: exports.pairingRoleSchema,
220
302
  transcriptHash: exports.pairingHashSchema,
221
303
  device: devices_1.deviceInfoSchema,
222
304
  presentation: exports.pairingDevicePresentationSchema,
223
305
  })
224
306
  .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
- })
307
+ /**
308
+ * Payload exchanged by `pairing.confirm` after the Connection handshake. The MAC uses the
309
+ * PAKE-derived confirmation key, proving the peer knew the code and saw the same transcript.
310
+ */
311
+ exports.pairingConfirmationSchema = exports.pairingConfirmationContentsSchema
312
+ .extend({ mac: exports.pairingHashSchema })
242
313
  .strict();
243
314
  /** Account credentials encrypted directly to the temporary destination identity. */
244
315
  exports.pairingCredentialContentsSchema = zod_1.z
@@ -250,7 +321,7 @@ exports.pairingCredentialContentsSchema = zod_1.z
250
321
  secretKey: base64UrlSchema.length(86),
251
322
  })
252
323
  .strict();
253
- /** Signed-and-boxed credential envelope sent over the WebRTC Connection. */
324
+ /** Signed-and-boxed credential envelope sent over the pairing Connection. */
254
325
  exports.pairingCredentialEnvelopeSchema = zod_1.z
255
326
  .object({
256
327
  contents: base64UrlSchema.min(1).max(4096),
@@ -275,12 +346,19 @@ exports.signedPairingInstallationReceiptSchema = zod_1.z
275
346
  publicKey: base64UrlSchema.length(43),
276
347
  })
277
348
  .strict();
278
- /** Renderer-visible phases of the short-lived pairing ceremony. */
349
+ /**
350
+ * Renderer-visible phases of the short-lived pairing ceremony.
351
+ *
352
+ * - `showing-code`: destination is displaying its code and waiting for a source to join.
353
+ * - `connecting`: room joined; transport negotiation and the Connection handshake are in progress.
354
+ * - `authenticating`: PAKE-derived confirmations are being exchanged.
355
+ * - `waiting-for-approval`: source must tap Approve; destination waits for it.
356
+ */
279
357
  exports.devicePairingPhaseSchema = zod_1.z.enum([
280
358
  "idle",
281
- "inviting",
359
+ "showing-code",
282
360
  "connecting",
283
- "comparing",
361
+ "authenticating",
284
362
  "waiting-for-approval",
285
363
  "transferring",
286
364
  "complete",
@@ -295,10 +373,10 @@ exports.devicePairingStateSchema = zod_1.z
295
373
  phase: exports.devicePairingPhaseSchema,
296
374
  expiresAt: zod_1.z.number().int().positive().optional(),
297
375
  remoteDevice: exports.pairingDevicePresentationSchema.optional(),
298
- sas: zod_1.z
299
- .string()
300
- .regex(/^\d{6}$/)
301
- .optional(),
376
+ /** Destination only: the code to show as text and QR while `showing-code`. */
377
+ code: zod_1.z.string().max(128).optional(),
378
+ /** Non-fatal message shown alongside the current phase (e.g. why a code was rotated). */
379
+ notice: zod_1.z.string().max(256).optional(),
302
380
  error: zod_1.z.string().max(256).optional(),
303
381
  })
304
382
  .strict();
package/dist/index.d.ts CHANGED
@@ -15,8 +15,8 @@ export * from "./device/socket-io-binary-peer";
15
15
  export * from "./device/tx-encoding";
16
16
  export * from "./device-pairing";
17
17
  export * from "./events";
18
- export * from "./group-invite";
19
18
  export * from "./hlc";
19
+ export * from "./invites";
20
20
  export * from "./keys";
21
21
  export * from "./logging";
22
22
  export * from "./mentions";
@@ -39,7 +39,6 @@ export * from "./types/workflow";
39
39
  export * from "./types/workflow-logger";
40
40
  export * from "./types/workflow-run-context";
41
41
  export * from "./types/zod-types";
42
- export * from "./user-connect";
43
42
  export * from "./users.query";
44
43
  export * from "./utils";
45
44
  export * from "./workflow-log-formatter";
package/dist/index.js CHANGED
@@ -36,8 +36,8 @@ __exportStar(require("./device/socket-io-binary-peer"), exports);
36
36
  __exportStar(require("./device/tx-encoding"), exports);
37
37
  __exportStar(require("./device-pairing"), exports);
38
38
  __exportStar(require("./events"), exports);
39
- __exportStar(require("./group-invite"), exports);
40
39
  __exportStar(require("./hlc"), exports);
40
+ __exportStar(require("./invites"), exports);
41
41
  __exportStar(require("./keys"), exports);
42
42
  __exportStar(require("./logging"), exports);
43
43
  __exportStar(require("./mentions"), exports);
@@ -60,7 +60,6 @@ __exportStar(require("./types/workflow"), exports);
60
60
  __exportStar(require("./types/workflow-logger"), exports);
61
61
  __exportStar(require("./types/workflow-run-context"), exports);
62
62
  __exportStar(require("./types/zod-types"), exports);
63
- __exportStar(require("./user-connect"), exports);
64
63
  __exportStar(require("./users.query"), exports);
65
64
  __exportStar(require("./utils"), exports);
66
65
  __exportStar(require("./workflow-log-formatter"), exports);
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ /** Encrypted box as produced by `boxDataWithKeys`. */
3
+ export declare const dataBoxSchema: z.ZodObject<{
4
+ contents: z.ZodString;
5
+ nonce: z.ZodString;
6
+ fromPublicKey: z.ZodString;
7
+ }, "strict", z.ZodTypeAny, {
8
+ nonce: string;
9
+ contents: string;
10
+ fromPublicKey: string;
11
+ }, {
12
+ nonce: string;
13
+ contents: string;
14
+ fromPublicKey: string;
15
+ }>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dataBoxSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ /** Encrypted box as produced by `boxDataWithKeys`. */
6
+ exports.dataBoxSchema = zod_1.z
7
+ .object({
8
+ contents: zod_1.z.string().min(1),
9
+ nonce: zod_1.z.string().min(1),
10
+ fromPublicKey: zod_1.z
11
+ .string()
12
+ .regex(/^[A-Za-z0-9_-]+$/)
13
+ .length(43),
14
+ })
15
+ .strict();
@@ -0,0 +1,43 @@
1
+ import type { UserContext } from "../context/user-context";
2
+ import { GroupMemberRole } from "../data";
3
+ import { type IPublicPrivateKeys } from "../keys";
4
+ import type { GroupApproval } from "./invite-messages";
5
+ import type { InviteIdentity } from "./invite-token";
6
+ /** Inputs for building a {@link GroupApproval} on the approving member's device. */
7
+ export interface BuildGroupApprovalInput {
8
+ groupId: string;
9
+ joiner: InviteIdentity;
10
+ role: GroupMemberRole;
11
+ /** Nonce of the token or direct invite this approval answers. */
12
+ inviteNonce?: string;
13
+ /** The approving user's keys; the group secret is read and boxed with these. */
14
+ approverKeys: IPublicPrivateKeys;
15
+ approverDeviceId: string;
16
+ }
17
+ /**
18
+ * Builds the approval payload for a joiner: signs their membership row, gathers Admin+
19
+ * seed rows plus the approver's own Users/Devices records, and boxes the group secret to
20
+ * the joiner's box key.
21
+ *
22
+ * The approver must hold Admin+ in the group. The membership row is signed and saved in
23
+ * the approver's group context here; it syncs to the joiner when they connect and is also
24
+ * carried in the payload so the joiner can seed their copy immediately.
25
+ *
26
+ * @throws when the group is unknown, the approver is not Admin+, or the secret is unavailable
27
+ */
28
+ export declare function buildGroupApproval(userContext: UserContext, input: BuildGroupApprovalInput): Promise<GroupApproval>;
29
+ /** Result of importing an approval on the joiner's device. */
30
+ export interface ImportGroupApprovalResult {
31
+ groupId: string;
32
+ approverUserId: string;
33
+ approverDeviceId: string;
34
+ }
35
+ /**
36
+ * Imports a {@link GroupApproval} on the joiner's device: records the group, seeds the group
37
+ * context with the signed rows, saves the approver as a contact, and stores the unboxed
38
+ * group secret in the personal context after validating it against the group's keys.
39
+ *
40
+ * Personal `Groups` is added only when missing so a local leave stays authoritative.
41
+ * `Devices` rows for the approver are left to the caller (device layer).
42
+ */
43
+ export declare function importGroupApproval(userContext: UserContext, approval: GroupApproval, joinerKeys: IPublicPrivateKeys): Promise<ImportGroupApprovalResult>;