memeloop 0.0.1 → 0.1.1

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 (228) hide show
  1. package/README.md +63 -0
  2. package/dist/browser.cjs +1413 -0
  3. package/dist/browser.cjs.map +1 -0
  4. package/dist/browser.d.cts +3066 -0
  5. package/dist/browser.d.ts +3066 -0
  6. package/dist/browser.js +43 -0
  7. package/dist/chunk-2C6BJZI3.js +382 -0
  8. package/dist/chunk-2C6BJZI3.js.map +1 -0
  9. package/dist/chunk-426CJUZP.js +630 -0
  10. package/dist/chunk-426CJUZP.js.map +1 -0
  11. package/dist/chunk-7ZDTB4VZ.js +63 -0
  12. package/dist/chunk-7ZDTB4VZ.js.map +1 -0
  13. package/dist/chunk-AZFYDWIN.js +98 -0
  14. package/dist/chunk-AZFYDWIN.js.map +1 -0
  15. package/dist/chunk-BGPU4RR7.js +367 -0
  16. package/dist/chunk-BGPU4RR7.js.map +1 -0
  17. package/dist/chunk-CCEFAOSH.js +496 -0
  18. package/dist/chunk-CCEFAOSH.js.map +1 -0
  19. package/dist/chunk-FWSY5HOA.js +63 -0
  20. package/dist/chunk-FWSY5HOA.js.map +1 -0
  21. package/dist/chunk-GYIOMQMY.js +8726 -0
  22. package/dist/chunk-GYIOMQMY.js.map +1 -0
  23. package/dist/chunk-K6P63KD4.js +68 -0
  24. package/dist/chunk-K6P63KD4.js.map +1 -0
  25. package/dist/chunk-KFS2EJT6.js +42 -0
  26. package/dist/chunk-KFS2EJT6.js.map +1 -0
  27. package/dist/chunk-MAJWHAKR.js +3637 -0
  28. package/dist/chunk-MAJWHAKR.js.map +1 -0
  29. package/dist/chunk-MRKY4HGF.js +205 -0
  30. package/dist/chunk-MRKY4HGF.js.map +1 -0
  31. package/dist/chunk-T7FSXWFR.js +2744 -0
  32. package/dist/chunk-T7FSXWFR.js.map +1 -0
  33. package/dist/chunk-VZKQX5PP.js +1 -0
  34. package/dist/chunk-VZKQX5PP.js.map +1 -0
  35. package/dist/chunk-WAI6BODI.js +175 -0
  36. package/dist/chunk-WAI6BODI.js.map +1 -0
  37. package/dist/chunk-YMNXDNDW.js +798 -0
  38. package/dist/chunk-YMNXDNDW.js.map +1 -0
  39. package/dist/conversation.cjs +208 -0
  40. package/dist/conversation.cjs.map +1 -0
  41. package/dist/conversation.d.cts +100 -0
  42. package/dist/conversation.d.ts +100 -0
  43. package/dist/conversation.js +21 -0
  44. package/dist/conversation.js.map +1 -0
  45. package/dist/device-network-portable.cjs +702 -0
  46. package/dist/device-network-portable.cjs.map +1 -0
  47. package/dist/device-network-portable.d.cts +110 -0
  48. package/dist/device-network-portable.d.ts +110 -0
  49. package/dist/device-network-portable.js +53 -0
  50. package/dist/device-network-portable.js.map +1 -0
  51. package/dist/device-network.cjs +906 -0
  52. package/dist/device-network.cjs.map +1 -0
  53. package/dist/device-network.d.cts +6 -0
  54. package/dist/device-network.d.ts +6 -0
  55. package/dist/device-network.js +59 -0
  56. package/dist/device-network.js.map +1 -0
  57. package/dist/fetchProvider-WWnWnQFP.d.ts +91 -0
  58. package/dist/fetchProvider-toTHy5Nu.d.cts +91 -0
  59. package/dist/index.cjs +28051 -5459
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.d.cts +94 -1320
  62. package/dist/index.d.ts +94 -1320
  63. package/dist/index.js +10616 -2420
  64. package/dist/index.js.map +1 -1
  65. package/dist/interface-IrKBFtL1.d.cts +493 -0
  66. package/dist/interface-IrKBFtL1.d.ts +493 -0
  67. package/dist/llm-providers.cjs +43 -8
  68. package/dist/llm-providers.cjs.map +1 -1
  69. package/dist/llm-providers.d.cts +2 -1
  70. package/dist/llm-providers.d.ts +2 -1
  71. package/dist/llm-providers.js +4 -2
  72. package/dist/llm-providers.js.map +1 -1
  73. package/dist/loop-api.cjs +5227 -2010
  74. package/dist/loop-api.cjs.map +1 -1
  75. package/dist/loop-api.d.cts +11 -5
  76. package/dist/loop-api.d.ts +11 -5
  77. package/dist/loop-api.js +86 -49
  78. package/dist/mobile.cjs +2711 -0
  79. package/dist/mobile.cjs.map +1 -0
  80. package/dist/mobile.d.cts +6 -0
  81. package/dist/mobile.d.ts +6 -0
  82. package/dist/mobile.js +22 -0
  83. package/dist/mobile.js.map +1 -0
  84. package/dist/orchestration-portable-BHB_YrNN.d.ts +2192 -0
  85. package/dist/orchestration-portable-mvYBvGBb.d.cts +2192 -0
  86. package/dist/orchestration-portable.cjs +9553 -0
  87. package/dist/orchestration-portable.cjs.map +1 -0
  88. package/dist/orchestration-portable.d.cts +5 -0
  89. package/dist/orchestration-portable.d.ts +5 -0
  90. package/dist/orchestration-portable.js +290 -0
  91. package/dist/orchestration-portable.js.map +1 -0
  92. package/dist/pairingInvite-BXPWY3aM.d.cts +149 -0
  93. package/dist/pairingInvite-Cuz0wuq9.d.ts +149 -0
  94. package/dist/promptConcat-0WNFTg4l.d.ts +516 -0
  95. package/dist/promptConcat-D6wr5V-V.d.cts +516 -0
  96. package/dist/providerRegistry-Bi6pAvSj.d.ts +86 -0
  97. package/dist/providerRegistry-CPsktuiX.d.cts +86 -0
  98. package/dist/registry-D0kbxksn.d.cts +393 -0
  99. package/dist/registry-DDbvhlhs.d.ts +393 -0
  100. package/dist/remoteClient-B_spK019.d.ts +87 -0
  101. package/dist/remoteClient-CBggnRy3.d.cts +87 -0
  102. package/dist/runtime-PGWR6FIV.js +18 -0
  103. package/dist/runtime-PGWR6FIV.js.map +1 -0
  104. package/dist/scriptDeploymentPipeline-CXJcC82H.d.ts +2464 -0
  105. package/dist/scriptDeploymentPipeline-yG1ZhVVI.d.cts +2464 -0
  106. package/dist/syncCloudDevices-BEqwgrhD.d.ts +49 -0
  107. package/dist/syncCloudDevices-Ds_Kcgrv.d.cts +49 -0
  108. package/dist/types-7pYti-k9.d.cts +255 -0
  109. package/dist/types-CdFVSntj.d.ts +255 -0
  110. package/package.json +110 -35
  111. package/dist/anthropic.cjs +0 -72
  112. package/dist/anthropic.cjs.map +0 -1
  113. package/dist/anthropic.d.cts +0 -21
  114. package/dist/anthropic.d.ts +0 -21
  115. package/dist/anthropic.js +0 -21
  116. package/dist/anthropic.js.map +0 -1
  117. package/dist/azure.cjs +0 -72
  118. package/dist/azure.cjs.map +0 -1
  119. package/dist/azure.d.cts +0 -21
  120. package/dist/azure.d.ts +0 -21
  121. package/dist/azure.js +0 -21
  122. package/dist/azure.js.map +0 -1
  123. package/dist/chunk-3CN7DFBL.js +0 -4894
  124. package/dist/chunk-3CN7DFBL.js.map +0 -1
  125. package/dist/chunk-4AZ4D7U5.js +0 -32
  126. package/dist/chunk-4AZ4D7U5.js.map +0 -1
  127. package/dist/chunk-6ON4XSOV.js +0 -63
  128. package/dist/chunk-6ON4XSOV.js.map +0 -1
  129. package/dist/chunk-DJQNGIXX.js +0 -4793
  130. package/dist/chunk-DJQNGIXX.js.map +0 -1
  131. package/dist/chunk-FKQP6AOQ.js +0 -32
  132. package/dist/chunk-FKQP6AOQ.js.map +0 -1
  133. package/dist/chunk-OVJ7JJBA.js +0 -35
  134. package/dist/chunk-OVJ7JJBA.js.map +0 -1
  135. package/dist/chunk-P4UZ7IXC.js +0 -42
  136. package/dist/chunk-YHJ2AEFR.js +0 -4933
  137. package/dist/chunk-YHJ2AEFR.js.map +0 -1
  138. package/dist/chunk-YVK7RYRO.js +0 -4973
  139. package/dist/chunk-YVK7RYRO.js.map +0 -1
  140. package/dist/code-assistant.json +0 -114
  141. package/dist/cohere.cjs +0 -72
  142. package/dist/cohere.cjs.map +0 -1
  143. package/dist/cohere.d.cts +0 -21
  144. package/dist/cohere.d.ts +0 -21
  145. package/dist/cohere.js +0 -21
  146. package/dist/cohere.js.map +0 -1
  147. package/dist/deepseek.cjs +0 -72
  148. package/dist/deepseek.cjs.map +0 -1
  149. package/dist/deepseek.d.cts +0 -21
  150. package/dist/deepseek.d.ts +0 -21
  151. package/dist/deepseek.js +0 -21
  152. package/dist/deepseek.js.map +0 -1
  153. package/dist/dist-65U7OYRG.js +0 -1257
  154. package/dist/dist-65U7OYRG.js.map +0 -1
  155. package/dist/fetchProvider-Cu4WkU5O.d.cts +0 -819
  156. package/dist/fetchProvider-Cu4WkU5O.d.ts +0 -819
  157. package/dist/frontend-ui-ux.json +0 -105
  158. package/dist/general-assistant.json +0 -95
  159. package/dist/git-master.json +0 -51
  160. package/dist/google-vertex.cjs +0 -72
  161. package/dist/google-vertex.cjs.map +0 -1
  162. package/dist/google-vertex.d.cts +0 -21
  163. package/dist/google-vertex.d.ts +0 -21
  164. package/dist/google-vertex.js +0 -21
  165. package/dist/google-vertex.js.map +0 -1
  166. package/dist/google.cjs +0 -72
  167. package/dist/google.cjs.map +0 -1
  168. package/dist/google.d.cts +0 -21
  169. package/dist/google.d.ts +0 -21
  170. package/dist/google.js +0 -21
  171. package/dist/google.js.map +0 -1
  172. package/dist/groq.cjs +0 -72
  173. package/dist/groq.cjs.map +0 -1
  174. package/dist/groq.d.cts +0 -21
  175. package/dist/groq.d.ts +0 -21
  176. package/dist/groq.js +0 -21
  177. package/dist/groq.js.map +0 -1
  178. package/dist/index.d.mts +0 -3203
  179. package/dist/index.mjs +0 -7064
  180. package/dist/index.mjs.map +0 -1
  181. package/dist/mistral.cjs +0 -72
  182. package/dist/mistral.cjs.map +0 -1
  183. package/dist/mistral.d.cts +0 -21
  184. package/dist/mistral.d.ts +0 -21
  185. package/dist/mistral.js +0 -21
  186. package/dist/mistral.js.map +0 -1
  187. package/dist/multipart-parser-EJCXIUHC.js +0 -372
  188. package/dist/multipart-parser-EJCXIUHC.js.map +0 -1
  189. package/dist/openai.cjs +0 -72
  190. package/dist/openai.cjs.map +0 -1
  191. package/dist/openai.d.cts +0 -21
  192. package/dist/openai.d.ts +0 -21
  193. package/dist/openai.js +0 -21
  194. package/dist/openai.js.map +0 -1
  195. package/dist/perplexity.cjs +0 -72
  196. package/dist/perplexity.cjs.map +0 -1
  197. package/dist/perplexity.d.cts +0 -21
  198. package/dist/perplexity.d.ts +0 -21
  199. package/dist/perplexity.js +0 -21
  200. package/dist/perplexity.js.map +0 -1
  201. package/dist/playwright.json +0 -52
  202. package/dist/promptConcat-BJdazTg5.d.cts +0 -1832
  203. package/dist/promptConcat-BJdazTg5.d.ts +0 -1832
  204. package/dist/promptConcat-CAkpni_8.d.cts +0 -1834
  205. package/dist/promptConcat-CAkpni_8.d.ts +0 -1834
  206. package/dist/promptConcat-CfH5-GAE.d.cts +0 -1036
  207. package/dist/promptConcat-ChcAZOOL.d.ts +0 -1036
  208. package/dist/promptConcat-G5TnJVRy.d.cts +0 -1800
  209. package/dist/promptConcat-G5TnJVRy.d.ts +0 -1800
  210. package/dist/promptConcat-L72eowzp.d.ts +0 -1090
  211. package/dist/promptConcat-eLHdN7K8.d.cts +0 -1090
  212. package/dist/src-VTSXKG72.js +0 -1409
  213. package/dist/src-VTSXKG72.js.map +0 -1
  214. package/dist/togetherai.cjs +0 -72
  215. package/dist/togetherai.cjs.map +0 -1
  216. package/dist/togetherai.d.cts +0 -21
  217. package/dist/togetherai.d.ts +0 -21
  218. package/dist/togetherai.js +0 -21
  219. package/dist/togetherai.js.map +0 -1
  220. package/dist/types-B0Jm2l38.d.cts +0 -767
  221. package/dist/types-B0Jm2l38.d.ts +0 -767
  222. package/dist/xai.cjs +0 -72
  223. package/dist/xai.cjs.map +0 -1
  224. package/dist/xai.d.cts +0 -21
  225. package/dist/xai.d.ts +0 -21
  226. package/dist/xai.js +0 -21
  227. package/dist/xai.js.map +0 -1
  228. /package/dist/{chunk-P4UZ7IXC.js.map → browser.js.map} +0 -0
@@ -0,0 +1,906 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/device-network-entry.ts
21
+ var device_network_entry_exports = {};
22
+ __export(device_network_entry_exports, {
23
+ ChatSyncEngine: () => ChatSyncEngine,
24
+ DEVICE_ORCHESTRATION_PROTOCOL: () => DEVICE_ORCHESTRATION_PROTOCOL,
25
+ DEVICE_PAIRING_INVITE_PROTOCOL: () => DEVICE_PAIRING_INVITE_PROTOCOL,
26
+ DEVICE_PAIRING_INVITE_TTL_MS: () => DEVICE_PAIRING_INVITE_TTL_MS,
27
+ LIBP2P_RPC_REQUEST_TYPE: () => LIBP2P_RPC_REQUEST_TYPE,
28
+ LIBP2P_RPC_RESPONSE_TYPE: () => LIBP2P_RPC_RESPONSE_TYPE,
29
+ LIBP2P_SYNC_REQUEST_TYPE: () => LIBP2P_SYNC_REQUEST_TYPE,
30
+ LIBP2P_SYNC_RESPONSE_TYPE: () => LIBP2P_SYNC_RESPONSE_TYPE,
31
+ Libp2pDeviceSyncTransport: () => Libp2pDeviceSyncTransport,
32
+ LocalTrustDeviceAuthorizer: () => LocalTrustDeviceAuthorizer,
33
+ MemoryDeviceNetworkService: () => MemoryDeviceNetworkService,
34
+ PeerNodeSyncAdapter: () => PeerNodeSyncAdapter,
35
+ attachmentBlobFromWire: () => attachmentBlobFromWire,
36
+ createDeviceOrchestrationStreamHandler: () => createDeviceOrchestrationStreamHandler,
37
+ createDeviceOrchestrationTransport: () => createDeviceOrchestrationTransport,
38
+ createDevicePairingInvite: () => createDevicePairingInvite,
39
+ decodeAttachmentBlobRpc: () => decodeAttachmentBlobRpc,
40
+ encodeDevicePairingInvite: () => encodeDevicePairingInvite,
41
+ isConversationMeta: () => isConversationMeta,
42
+ isLibp2pRpcRequest: () => isLibp2pRpcRequest,
43
+ isLibp2pRpcResponse: () => isLibp2pRpcResponse,
44
+ isLibp2pSyncRequest: () => isLibp2pSyncRequest,
45
+ isLibp2pSyncResponse: () => isLibp2pSyncResponse,
46
+ parseDevicePairingInvite: () => parseDevicePairingInvite,
47
+ syncCloudDevices: () => syncCloudDevices
48
+ });
49
+ module.exports = __toCommonJS(device_network_entry_exports);
50
+
51
+ // src/orchestration/errors.ts
52
+ var OrchestrationError = class extends Error {
53
+ code;
54
+ retryable;
55
+ retryAfterMs;
56
+ reason;
57
+ details;
58
+ constructor(data) {
59
+ super(data.message);
60
+ this.name = "OrchestrationError";
61
+ this.code = data.code;
62
+ this.retryable = data.retryable;
63
+ this.retryAfterMs = data.retryAfterMs;
64
+ this.reason = data.reason;
65
+ this.details = data.details;
66
+ }
67
+ toJSON() {
68
+ return {
69
+ code: this.code,
70
+ message: this.message,
71
+ retryable: this.retryable,
72
+ retryAfterMs: this.retryAfterMs,
73
+ reason: this.reason,
74
+ details: this.details
75
+ };
76
+ }
77
+ };
78
+
79
+ // src/device-network/deviceOrchestrationTransport.ts
80
+ var DEVICE_ORCHESTRATION_PROTOCOL = "/memeloop/orchestration/1.0.0";
81
+ var DEFAULT_MAX_FRAME_BYTES = 1024 * 1024;
82
+ function orchestrationTransportError(code, message) {
83
+ return new OrchestrationError({
84
+ code,
85
+ message,
86
+ retryable: code === "UNAVAILABLE"
87
+ });
88
+ }
89
+ function assertFrameLimit(limit) {
90
+ if (!Number.isSafeInteger(limit) || limit < 256) {
91
+ throw new TypeError("maxFrameBytes must be a safe integer of at least 256");
92
+ }
93
+ }
94
+ async function* encodeLines(values, maxFrameBytes) {
95
+ const encoder = new TextEncoder();
96
+ for await (const value of values) {
97
+ const frame = encoder.encode(`${JSON.stringify(value)}
98
+ `);
99
+ if (frame.byteLength > maxFrameBytes) {
100
+ throw orchestrationTransportError(
101
+ "EXHAUSTED",
102
+ `device orchestration frame exceeds ${maxFrameBytes} bytes`
103
+ );
104
+ }
105
+ yield frame;
106
+ }
107
+ }
108
+ async function* decodeLines(source, maxFrameBytes) {
109
+ const decoder = new TextDecoder();
110
+ let buffered = "";
111
+ for await (const chunk of source) {
112
+ buffered += decoder.decode(chunk, { stream: true });
113
+ for (; ; ) {
114
+ const newline = buffered.indexOf("\n");
115
+ if (newline < 0) break;
116
+ const line = buffered.slice(0, newline);
117
+ buffered = buffered.slice(newline + 1);
118
+ if (!line) continue;
119
+ if (new TextEncoder().encode(line).byteLength > maxFrameBytes) {
120
+ throw orchestrationTransportError(
121
+ "EXHAUSTED",
122
+ `device orchestration frame exceeds ${maxFrameBytes} bytes`
123
+ );
124
+ }
125
+ try {
126
+ yield JSON.parse(line);
127
+ } catch {
128
+ throw orchestrationTransportError(
129
+ "INVALID",
130
+ "device orchestration stream contains invalid JSON"
131
+ );
132
+ }
133
+ }
134
+ if (new TextEncoder().encode(buffered).byteLength > maxFrameBytes) {
135
+ throw orchestrationTransportError(
136
+ "EXHAUSTED",
137
+ `device orchestration frame exceeds ${maxFrameBytes} bytes`
138
+ );
139
+ }
140
+ }
141
+ buffered += decoder.decode();
142
+ if (buffered.trim()) {
143
+ try {
144
+ yield JSON.parse(buffered);
145
+ } catch {
146
+ throw orchestrationTransportError(
147
+ "INVALID",
148
+ "device orchestration stream contains invalid trailing JSON"
149
+ );
150
+ }
151
+ }
152
+ }
153
+ function throwIfAborted(signal) {
154
+ if (signal?.aborted) {
155
+ throw orchestrationTransportError("CANCELLED", "device orchestration request was cancelled");
156
+ }
157
+ }
158
+ async function openAuthenticatedStream(options) {
159
+ const grant = await options.grantProvider?.(options.peerId);
160
+ return {
161
+ stream: await options.deviceNetwork.openStream(
162
+ options.peerId,
163
+ DEVICE_ORCHESTRATION_PROTOCOL,
164
+ grant
165
+ ),
166
+ grant
167
+ };
168
+ }
169
+ async function writeRequest(stream, request, grant, maxFrameBytes) {
170
+ const envelope = {
171
+ type: "memeloop-device-orchestration-request-v1",
172
+ request,
173
+ ...grant ? { grant } : {}
174
+ };
175
+ await stream.sink(encodeLines([envelope], maxFrameBytes));
176
+ }
177
+ function createDeviceOrchestrationTransport(options) {
178
+ const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES;
179
+ assertFrameLimit(maxFrameBytes);
180
+ return {
181
+ async request(request, transportOptions = {}) {
182
+ throwIfAborted(transportOptions.signal);
183
+ const { stream, grant } = await openAuthenticatedStream(options);
184
+ const closeOnAbort = () => {
185
+ void stream.close();
186
+ };
187
+ transportOptions.signal?.addEventListener("abort", closeOnAbort, {
188
+ once: true
189
+ });
190
+ try {
191
+ await writeRequest(stream, request, grant, maxFrameBytes);
192
+ let response;
193
+ for await (const value of decodeLines(stream.source, maxFrameBytes)) {
194
+ if (response) {
195
+ throw orchestrationTransportError(
196
+ "INVALID",
197
+ "device orchestration request returned multiple responses"
198
+ );
199
+ }
200
+ response = value;
201
+ }
202
+ throwIfAborted(transportOptions.signal);
203
+ if (!response) {
204
+ throw orchestrationTransportError(
205
+ "UNAVAILABLE",
206
+ "device orchestration request returned no response"
207
+ );
208
+ }
209
+ return response;
210
+ } finally {
211
+ transportOptions.signal?.removeEventListener("abort", closeOnAbort);
212
+ await stream.close().catch(() => void 0);
213
+ }
214
+ },
215
+ async *watch(request, transportOptions = {}) {
216
+ throwIfAborted(transportOptions.signal);
217
+ const { stream, grant } = await openAuthenticatedStream(options);
218
+ const closeOnAbort = () => {
219
+ void stream.close();
220
+ };
221
+ transportOptions.signal?.addEventListener("abort", closeOnAbort, {
222
+ once: true
223
+ });
224
+ try {
225
+ await writeRequest(stream, request, grant, maxFrameBytes);
226
+ for await (const value of decodeLines(stream.source, maxFrameBytes)) {
227
+ throwIfAborted(transportOptions.signal);
228
+ yield value;
229
+ }
230
+ throwIfAborted(transportOptions.signal);
231
+ } finally {
232
+ transportOptions.signal?.removeEventListener("abort", closeOnAbort);
233
+ await stream.close().catch(() => void 0);
234
+ }
235
+ }
236
+ };
237
+ }
238
+ async function readSingleRequest(stream, maxFrameBytes) {
239
+ let envelope;
240
+ for await (const value of decodeLines(stream.source, maxFrameBytes)) {
241
+ if (envelope) {
242
+ throw orchestrationTransportError(
243
+ "INVALID",
244
+ "device orchestration stream accepts exactly one request"
245
+ );
246
+ }
247
+ if (value === null || typeof value !== "object" || Array.isArray(value) || value.type !== "memeloop-device-orchestration-request-v1" || value.request === null || typeof value.request !== "object") {
248
+ throw orchestrationTransportError(
249
+ "INVALID",
250
+ "device orchestration request envelope is invalid"
251
+ );
252
+ }
253
+ envelope = value;
254
+ }
255
+ if (!envelope) {
256
+ throw orchestrationTransportError("INVALID", "device orchestration request is missing");
257
+ }
258
+ return envelope;
259
+ }
260
+ function createDeviceOrchestrationStreamHandler(options) {
261
+ const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES;
262
+ assertFrameLimit(maxFrameBytes);
263
+ return async ({ remotePeerId, stream, authorize }) => {
264
+ const abort = new AbortController();
265
+ try {
266
+ const envelope = await readSingleRequest(stream, maxFrameBytes);
267
+ if (authorize && !await authorize(envelope.grant)) {
268
+ throw orchestrationTransportError("UNAVAILABLE", "device_not_trusted");
269
+ }
270
+ const request = envelope.request;
271
+ const handler = await options.resolveHandler(remotePeerId);
272
+ if (request.operation === "watch") {
273
+ await stream.sink(
274
+ encodeLines(handler.watch(request, { signal: abort.signal }), maxFrameBytes)
275
+ );
276
+ } else {
277
+ await stream.sink(encodeLines([await handler.request(request)], maxFrameBytes));
278
+ }
279
+ } finally {
280
+ abort.abort();
281
+ await stream.close().catch(() => void 0);
282
+ }
283
+ };
284
+ }
285
+
286
+ // src/device-network/libp2pSyncProtocol.ts
287
+ var LIBP2P_SYNC_REQUEST_TYPE = "memeloop-sync-request-v1";
288
+ var LIBP2P_SYNC_RESPONSE_TYPE = "memeloop-sync-response-v1";
289
+ var syncMethods = /* @__PURE__ */ new Set([
290
+ "exchangeVersionVector",
291
+ "pullMissingMetadata",
292
+ "pullMissingMessages",
293
+ "pullAttachmentBlob"
294
+ ]);
295
+ function isLibp2pSyncRequest(value) {
296
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
297
+ const record = value;
298
+ return record.type === LIBP2P_SYNC_REQUEST_TYPE && typeof record.id === "string" && typeof record.method === "string" && syncMethods.has(record.method);
299
+ }
300
+ function isLibp2pSyncResponse(value) {
301
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
302
+ const record = value;
303
+ if (record.type !== LIBP2P_SYNC_RESPONSE_TYPE || typeof record.id !== "string" || typeof record.ok !== "boolean") return false;
304
+ if (record.ok) return "result" in record;
305
+ return typeof record.error === "string";
306
+ }
307
+ function isAttachmentBlobWire(value) {
308
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
309
+ const record = value;
310
+ return typeof record.dataBase64Url === "string" && typeof record.filename === "string" && typeof record.mimeType === "string" && typeof record.size === "number";
311
+ }
312
+ async function attachmentBlobFromWire(value) {
313
+ if (value === null) return null;
314
+ if (!isAttachmentBlobWire(value)) throw new Error("invalid_sync_response");
315
+ let data;
316
+ try {
317
+ const base64 = value.dataBase64Url.replace(/-/g, "+").replace(/_/g, "/");
318
+ const paddedBase64 = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
319
+ const binary = atob(paddedBase64);
320
+ data = Uint8Array.from(binary, (character) => character.charCodeAt(0));
321
+ } catch {
322
+ throw new Error("invalid_sync_response");
323
+ }
324
+ return {
325
+ data,
326
+ filename: value.filename,
327
+ mimeType: value.mimeType,
328
+ size: value.size
329
+ };
330
+ }
331
+
332
+ // src/device-network/libp2pDeviceSyncTransport.ts
333
+ var Libp2pDeviceSyncTransport = class {
334
+ nodeId;
335
+ deviceNetwork;
336
+ grantProvider;
337
+ constructor(options) {
338
+ this.nodeId = options.nodeId;
339
+ this.deviceNetwork = options.deviceNetwork;
340
+ this.grantProvider = options.grantProvider;
341
+ }
342
+ listPeers() {
343
+ return this.deviceNetwork.listDevices();
344
+ }
345
+ exchangeVersionVector(peerId, localVersion) {
346
+ return this.request(peerId, "exchangeVersionVector", { localVersion });
347
+ }
348
+ pullMissingMetadata(peerId, sinceVersion) {
349
+ return this.request(peerId, "pullMissingMetadata", { sinceVersion });
350
+ }
351
+ pullMissingMessages(peerId, conversationId, knownMessageIds) {
352
+ return this.request(peerId, "pullMissingMessages", { conversationId, knownMessageIds });
353
+ }
354
+ async pullAttachmentBlob(peerId, contentHash) {
355
+ const result = await this.request(peerId, "pullAttachmentBlob", { contentHash });
356
+ return attachmentBlobFromWire(result);
357
+ }
358
+ async request(peerId, method, parameters) {
359
+ const grant = await this.grantProvider?.(peerId);
360
+ const stream = await this.deviceNetwork.openStream(peerId, "/memeloop/sync/1.0.0", grant);
361
+ const request = {
362
+ type: LIBP2P_SYNC_REQUEST_TYPE,
363
+ id: crypto.randomUUID(),
364
+ method,
365
+ params: parameters,
366
+ grant
367
+ };
368
+ await writeJsonToStream(stream, request);
369
+ const response = await readJsonFromStream(stream);
370
+ await stream.close();
371
+ if (!isLibp2pSyncResponse(response)) throw new Error("invalid_sync_response");
372
+ if (response.id !== request.id) throw new Error("sync_response_id_mismatch");
373
+ if (!response.ok) throw new Error(response.error);
374
+ return response.result;
375
+ }
376
+ };
377
+ async function writeJsonToStream(stream, message) {
378
+ const payload = new TextEncoder().encode(JSON.stringify(message));
379
+ await stream.sink((async function* () {
380
+ yield payload;
381
+ })());
382
+ }
383
+ async function readJsonFromStream(stream) {
384
+ const reader = stream.source[Symbol.asyncIterator]();
385
+ const result = await reader.next();
386
+ if (result.done || !result.value) throw new Error("sync_response_missing");
387
+ return JSON.parse(new TextDecoder().decode(result.value));
388
+ }
389
+
390
+ // src/device-network/libp2pRpcProtocol.ts
391
+ var LIBP2P_RPC_REQUEST_TYPE = "memeloop-rpc-request-v1";
392
+ var LIBP2P_RPC_RESPONSE_TYPE = "memeloop-rpc-response-v1";
393
+ function isLibp2pRpcRequest(value) {
394
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
395
+ const record = value;
396
+ return record.type === LIBP2P_RPC_REQUEST_TYPE && typeof record.id === "string" && typeof record.method === "string";
397
+ }
398
+ function isLibp2pRpcResponse(value) {
399
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
400
+ const record = value;
401
+ if (record.type !== LIBP2P_RPC_RESPONSE_TYPE || typeof record.id !== "string" || typeof record.ok !== "boolean") return false;
402
+ if (record.ok) return "result" in record;
403
+ return typeof record.error === "string";
404
+ }
405
+
406
+ // src/device-network/localTrustDeviceAuthorizer.ts
407
+ var PAIRING_PROTOCOL = "/memeloop/pairing/1.0.0";
408
+ var LocalTrustDeviceAuthorizer = class {
409
+ constructor(options = {}) {
410
+ this.options = options;
411
+ this.allowPairingProtocol = options.allowPairingProtocol ?? true;
412
+ for (const record of options.trustedDevices ?? []) {
413
+ this.trustedDevices.set(record.peerId, record);
414
+ }
415
+ }
416
+ trustedDevices = /* @__PURE__ */ new Map();
417
+ allowPairingProtocol;
418
+ setTrustedDevice(record) {
419
+ this.trustedDevices.set(record.peerId, record);
420
+ }
421
+ removeTrustedDevice(peerId) {
422
+ this.trustedDevices.delete(peerId);
423
+ }
424
+ async canOpenProtocol(input) {
425
+ const record = this.options.getTrustedDevice?.(input.remotePeerId) ?? this.trustedDevices.get(input.remotePeerId);
426
+ if (record?.revokedAt) return false;
427
+ if (input.protocol === PAIRING_PROTOCOL) return this.allowPairingProtocol;
428
+ return record !== void 0;
429
+ }
430
+ };
431
+
432
+ // src/device-network/pairingInvite.ts
433
+ var DEVICE_PAIRING_INVITE_PROTOCOL = "memeloop-device-pairing-v1";
434
+ var DEVICE_PAIRING_INVITE_TTL_MS = 5 * 6e4;
435
+ var MAX_INVITE_LENGTH = 16 * 1024;
436
+ var MAX_ADDRESSES = 8;
437
+ function requireText(value, name, maxLength) {
438
+ const trimmed = value.trim();
439
+ if (!trimmed || trimmed.length > maxLength) {
440
+ throw new Error(`invalid device pairing invite ${name}`);
441
+ }
442
+ return trimmed;
443
+ }
444
+ function validateAddresses(addresses) {
445
+ const unique = [...new Set(addresses.map((address) => address.trim()))].filter(Boolean);
446
+ if (unique.length === 0 || unique.length > MAX_ADDRESSES || unique.some(
447
+ (address) => address.length > 2048 || !address.startsWith("/") || !address.includes("/ws") && !address.includes("/wss")
448
+ )) {
449
+ throw new Error("device pairing invite requires WebSocket multiaddrs");
450
+ }
451
+ return unique;
452
+ }
453
+ function createDevicePairingInvite(device, options = {}) {
454
+ const createdAt = options.now ?? Date.now();
455
+ const ttlMs = options.ttlMs ?? DEVICE_PAIRING_INVITE_TTL_MS;
456
+ if (!Number.isSafeInteger(createdAt) || !Number.isSafeInteger(ttlMs) || ttlMs <= 0 || ttlMs > DEVICE_PAIRING_INVITE_TTL_MS) {
457
+ throw new Error("invalid device pairing invite lifetime");
458
+ }
459
+ return {
460
+ protocol: DEVICE_PAIRING_INVITE_PROTOCOL,
461
+ peerId: requireText(device.peerId, "peerId", 256),
462
+ deviceName: requireText(device.displayName, "deviceName", 256),
463
+ multiaddrs: validateAddresses(device.multiaddrs ?? []),
464
+ createdAt,
465
+ expiresAt: createdAt + ttlMs
466
+ };
467
+ }
468
+ function encodeDevicePairingInvite(invite) {
469
+ const validated = parseDevicePairingInvite(JSON.stringify(invite), {
470
+ now: invite.createdAt
471
+ });
472
+ return JSON.stringify(validated);
473
+ }
474
+ function parseDevicePairingInvite(serialized, options = {}) {
475
+ if (!serialized || serialized.length > MAX_INVITE_LENGTH) {
476
+ throw new Error("invalid device pairing invite length");
477
+ }
478
+ let parsed;
479
+ try {
480
+ parsed = JSON.parse(serialized);
481
+ } catch {
482
+ throw new Error("device pairing invite is not valid JSON");
483
+ }
484
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
485
+ throw new Error("invalid device pairing invite");
486
+ }
487
+ const record = parsed;
488
+ if (record.protocol !== DEVICE_PAIRING_INVITE_PROTOCOL || typeof record.peerId !== "string" || typeof record.deviceName !== "string" || !Array.isArray(record.multiaddrs) || record.multiaddrs.some((address) => typeof address !== "string") || typeof record.createdAt !== "number" || typeof record.expiresAt !== "number" || !Number.isSafeInteger(record.createdAt) || !Number.isSafeInteger(record.expiresAt) || record.expiresAt <= record.createdAt || record.expiresAt - record.createdAt > DEVICE_PAIRING_INVITE_TTL_MS) {
489
+ throw new Error("invalid device pairing invite");
490
+ }
491
+ if (record.expiresAt <= (options.now ?? Date.now())) {
492
+ throw new Error("device pairing invite has expired");
493
+ }
494
+ return {
495
+ protocol: DEVICE_PAIRING_INVITE_PROTOCOL,
496
+ peerId: requireText(record.peerId, "peerId", 256),
497
+ deviceName: requireText(record.deviceName, "deviceName", 256),
498
+ multiaddrs: validateAddresses(record.multiaddrs),
499
+ createdAt: record.createdAt,
500
+ expiresAt: record.expiresAt
501
+ };
502
+ }
503
+
504
+ // src/sync/attachmentRpcCodec.ts
505
+ function decodeAttachmentBlobRpc(result) {
506
+ if (result == null || typeof result !== "object") return null;
507
+ const r = result;
508
+ if (r.error || !r.found || typeof r.dataBase64 !== "string") return null;
509
+ let data;
510
+ try {
511
+ const binary = atob(r.dataBase64);
512
+ if (!binary.length) return null;
513
+ data = Uint8Array.from(binary, (character) => character.charCodeAt(0));
514
+ } catch {
515
+ return null;
516
+ }
517
+ return {
518
+ data,
519
+ filename: typeof r.filename === "string" ? r.filename : "attachment",
520
+ mimeType: typeof r.mimeType === "string" ? r.mimeType : "application/octet-stream",
521
+ size: typeof r.size === "number" && r.size > 0 ? r.size : data.byteLength
522
+ };
523
+ }
524
+
525
+ // src/sync/chatSyncEngine.ts
526
+ var ChatSyncEngine = class {
527
+ nodeId;
528
+ storage;
529
+ getPeers;
530
+ versionVector = {};
531
+ constructor(options) {
532
+ this.nodeId = options.nodeId;
533
+ this.storage = options.storage;
534
+ this.getPeers = options.peers;
535
+ this.versionVector[this.nodeId] = 0;
536
+ }
537
+ /**
538
+ * 在本节点新产生一条消息时调用,增加本节点的 lamportClock。
539
+ */
540
+ bumpLocalVersion() {
541
+ this.versionVector[this.nodeId] = (this.versionVector[this.nodeId] ?? 0) + 1;
542
+ }
543
+ /**
544
+ * 执行一次与所有 peer 的增量同步(metadata 级别),并尽力拉取缺失消息。
545
+ */
546
+ async syncOnce() {
547
+ const peers = this.getPeers();
548
+ if (peers.length === 0) return;
549
+ const localVersion = { ...this.versionVector };
550
+ const pulledConversations = /* @__PURE__ */ new Set();
551
+ for (const peer of peers) {
552
+ const { remoteVersion, missingForRemote } = await peer.exchangeVersionVector(localVersion);
553
+ const missingForLocal = await peer.pullMissingMetadata(this.versionVector);
554
+ for (const meta of missingForLocal) {
555
+ await this.storage.upsertConversationMetadata(meta);
556
+ pulledConversations.add(meta.conversationId);
557
+ }
558
+ for (const [nodeId, clock] of Object.entries(remoteVersion)) {
559
+ const current = this.versionVector[nodeId] ?? 0;
560
+ if (clock > current) {
561
+ this.versionVector[nodeId] = clock;
562
+ }
563
+ }
564
+ if (missingForRemote.length > 0) {
565
+ this.bumpLocalVersion();
566
+ }
567
+ }
568
+ for (const conversationId of pulledConversations) {
569
+ await this.pullMessagesForConversationFromPeers(conversationId, peers);
570
+ }
571
+ }
572
+ /**
573
+ * Anti-entropy:先 syncOnce,再对已知会话逐个向各 peer 拉取缺失消息(参考审查单「定期对账」)。
574
+ */
575
+ async antiEntropyOnce() {
576
+ await this.syncOnce();
577
+ const list = await this.storage.listConversations({ limit: 500 });
578
+ const peers = this.getPeers();
579
+ for (const meta of list) {
580
+ await this.pullMessagesForConversationFromPeers(meta.conversationId, peers);
581
+ }
582
+ }
583
+ async pullMessagesForConversationFromPeers(conversationId, peers) {
584
+ const localMsgs = await this.storage.getMessages(conversationId, { mode: "full-content" });
585
+ const knownIds = localMsgs.map((m) => m.messageId);
586
+ for (const peer of peers) {
587
+ if (!peer.pullMissingMessages) continue;
588
+ try {
589
+ const incoming = await peer.pullMissingMessages(conversationId, knownIds);
590
+ if (incoming.length > 0) {
591
+ await this.storage.insertMessagesIfAbsent(incoming);
592
+ await this.ensureAttachmentsFromMessages(incoming, peers);
593
+ }
594
+ } catch {
595
+ }
596
+ }
597
+ }
598
+ /** 从消息元数据收集 `attachments[].contentHash`,对本地缺失 BLOB 的哈希向各 peer 拉取并 `saveAttachment`。 */
599
+ async ensureAttachmentsFromMessages(messages, peers) {
600
+ const hashes = /* @__PURE__ */ new Set();
601
+ for (const m of messages) {
602
+ for (const a of m.attachments ?? []) {
603
+ if (a.contentHash) hashes.add(a.contentHash);
604
+ }
605
+ }
606
+ for (const h of hashes) {
607
+ const reference = await this.storage.getAttachment(h);
608
+ if (reference) {
609
+ const reader = this.storage.readAttachmentData?.bind(this.storage);
610
+ if (!reader) continue;
611
+ const bytes = await reader(h);
612
+ if (bytes && bytes.length > 0) continue;
613
+ }
614
+ for (const peer of peers) {
615
+ const pull = peer.pullAttachmentBlob?.bind(peer);
616
+ if (!pull) continue;
617
+ try {
618
+ const blob = await pull(h);
619
+ if (blob?.data?.length) {
620
+ const ar = {
621
+ contentHash: h,
622
+ filename: blob.filename,
623
+ mimeType: blob.mimeType,
624
+ size: blob.size > 0 ? blob.size : blob.data.length
625
+ };
626
+ await this.storage.saveAttachment(ar, blob.data);
627
+ break;
628
+ }
629
+ } catch {
630
+ }
631
+ }
632
+ }
633
+ }
634
+ getVersionVector() {
635
+ return { ...this.versionVector };
636
+ }
637
+ getStorage() {
638
+ return this.storage;
639
+ }
640
+ };
641
+
642
+ // src/sync/peerNodeAdapter.ts
643
+ var PeerNodeSyncAdapter = class {
644
+ nodeId;
645
+ transport;
646
+ constructor(nodeId, transport) {
647
+ this.nodeId = nodeId;
648
+ this.transport = transport;
649
+ }
650
+ exchangeVersionVector(localVersion) {
651
+ return this.transport.exchangeVersionVector(this.nodeId, localVersion);
652
+ }
653
+ pullMissingMetadata(sinceVersion) {
654
+ return this.transport.pullMissingMetadata(this.nodeId, sinceVersion);
655
+ }
656
+ pullMissingMessages(conversationId, knownMessageIds) {
657
+ const function_ = this.transport.pullMissingMessages?.bind(this.transport);
658
+ if (!function_) {
659
+ return Promise.resolve([]);
660
+ }
661
+ return function_(this.nodeId, conversationId, knownMessageIds);
662
+ }
663
+ pullAttachmentBlob(contentHash) {
664
+ const function_ = this.transport.pullAttachmentBlob?.bind(this.transport);
665
+ if (!function_) {
666
+ return Promise.resolve(null);
667
+ }
668
+ return function_(this.nodeId, contentHash);
669
+ }
670
+ };
671
+
672
+ // src/sync/protocol.ts
673
+ function isConversationMeta(value) {
674
+ if (value === null || typeof value !== "object") return false;
675
+ const o = value;
676
+ return typeof o.conversationId === "string" && typeof o.title === "string" && typeof o.originNodeId === "string" && typeof o.definitionId === "string" && typeof o.messageCount === "number" && typeof o.lastMessageTimestamp === "number" && typeof o.isUserInitiated === "boolean";
677
+ }
678
+
679
+ // src/device-network/memoryDeviceNetworkService.ts
680
+ var emptyCapabilities = {
681
+ tools: [],
682
+ mcpServers: [],
683
+ hasWiki: false,
684
+ agentLoop: false,
685
+ imChannels: [],
686
+ wikis: []
687
+ };
688
+ function toDevice(record, capabilities) {
689
+ return {
690
+ peerId: record.peerId,
691
+ displayName: record.deviceName,
692
+ platform: record.platform,
693
+ trustMode: record.trustMode,
694
+ trusted: !record.revokedAt,
695
+ reachability: {
696
+ state: record.revokedAt ? "offline" : "nearby",
697
+ paths: record.revokedAt ? [] : ["lan"]
698
+ },
699
+ capabilities,
700
+ lastSeen: record.lastSeen
701
+ };
702
+ }
703
+ var MemoryDeviceNetworkService = class {
704
+ constructor(options) {
705
+ this.options = options;
706
+ this.capabilities = options.capabilities ?? emptyCapabilities;
707
+ for (const record of options.trustedDevices ?? []) {
708
+ this.trustedDevices.set(record.peerId, record);
709
+ }
710
+ }
711
+ started = false;
712
+ capabilities;
713
+ trustedDevices = /* @__PURE__ */ new Map();
714
+ pairingSessions = /* @__PURE__ */ new Map();
715
+ listeners = /* @__PURE__ */ new Set();
716
+ pairingListeners = /* @__PURE__ */ new Set();
717
+ async start() {
718
+ this.started = true;
719
+ this.emitDevices();
720
+ }
721
+ async stop() {
722
+ this.started = false;
723
+ this.emitDevices();
724
+ }
725
+ async getLocalDevice() {
726
+ return {
727
+ peerId: this.options.identity.peerId,
728
+ displayName: this.options.identity.deviceName,
729
+ platform: this.options.identity.platform,
730
+ trustMode: "local-pairing",
731
+ reachability: {
732
+ state: this.started ? "online" : "offline",
733
+ paths: this.started ? ["lan"] : []
734
+ },
735
+ capabilities: this.capabilities,
736
+ lastSeen: Date.now()
737
+ };
738
+ }
739
+ async listDevices() {
740
+ return [...this.trustedDevices.values()].map((record) => toDevice(record, emptyCapabilities));
741
+ }
742
+ observeDevices(listener) {
743
+ this.listeners.add(listener);
744
+ void this.listDevices().then(listener);
745
+ return () => {
746
+ this.listeners.delete(listener);
747
+ };
748
+ }
749
+ async listPairingSessions() {
750
+ return [...this.pairingSessions.values()];
751
+ }
752
+ observePairingSessions(listener) {
753
+ this.pairingListeners.add(listener);
754
+ void this.listPairingSessions().then(listener);
755
+ return () => {
756
+ this.pairingListeners.delete(listener);
757
+ };
758
+ }
759
+ async requestLocalPairing(peerId, _options = {}) {
760
+ const createdAt = Date.now();
761
+ const session = {
762
+ sessionId: `pairing-${this.options.identity.peerId}-${peerId}-${createdAt}`,
763
+ localPeerId: this.options.identity.peerId,
764
+ remotePeerId: peerId,
765
+ remotePublicKeyMultibase: "",
766
+ remoteDeviceName: peerId,
767
+ remotePlatform: "cli",
768
+ remoteCapabilities: emptyCapabilities,
769
+ remoteMultiaddrs: [],
770
+ direction: "outbound",
771
+ status: "pending",
772
+ confirmCode: this.confirmCode(peerId),
773
+ createdAt,
774
+ expiresAt: createdAt + 5 * 6e4
775
+ };
776
+ this.pairingSessions.set(session.sessionId, session);
777
+ this.emitPairingSessions();
778
+ return session;
779
+ }
780
+ async acceptPairing(sessionId) {
781
+ const session = this.pairingSessions.get(sessionId);
782
+ if (!session) throw new Error("pairing_session_not_found");
783
+ if (session.expiresAt < Date.now()) throw new Error("pairing_session_expired");
784
+ if (session.status !== "pending") throw new Error("pairing_session_not_pending");
785
+ this.trustedDevices.set(session.remotePeerId, {
786
+ peerId: session.remotePeerId,
787
+ publicKeyMultibase: session.remotePublicKeyMultibase,
788
+ deviceName: session.remoteDeviceName,
789
+ platform: session.remotePlatform,
790
+ trustMode: "local-pairing",
791
+ createdAt: Date.now(),
792
+ lastSeen: Date.now()
793
+ });
794
+ session.status = "accepted";
795
+ this.emitPairingSessions();
796
+ this.emitDevices();
797
+ }
798
+ async rejectPairing(sessionId) {
799
+ const session = this.pairingSessions.get(sessionId);
800
+ if (!session) return;
801
+ session.status = "rejected";
802
+ this.emitPairingSessions();
803
+ }
804
+ async removeTrustedDevice(peerId) {
805
+ this.trustedDevices.delete(peerId);
806
+ this.emitDevices();
807
+ }
808
+ async openStream(peerId, _protocol, _presentedGrant) {
809
+ if (!this.trustedDevices.has(peerId)) throw new Error("device_not_trusted");
810
+ return {
811
+ source: (async function* emptySource() {
812
+ })(),
813
+ async sink() {
814
+ },
815
+ async close() {
816
+ }
817
+ };
818
+ }
819
+ async sendRpc(peerId, _method, _parameters, _presentedGrant) {
820
+ if (!this.trustedDevices.has(peerId)) throw new Error("device_not_trusted");
821
+ throw new Error("rpc_handler_not_registered");
822
+ }
823
+ async syncWithDevice(peerId, _presentedGrant) {
824
+ if (!this.trustedDevices.has(peerId)) throw new Error("device_not_trusted");
825
+ return { ok: true, peerId, syncedAt: Date.now() };
826
+ }
827
+ confirmCode(peerId) {
828
+ const input = `${this.options.identity.peerId}:${peerId}`;
829
+ let hash = 0;
830
+ for (let index = 0; index < input.length; index += 1) {
831
+ hash = hash * 31 + input.charCodeAt(index) >>> 0;
832
+ }
833
+ return (hash % 1e6).toString().padStart(6, "0");
834
+ }
835
+ emitDevices() {
836
+ void this.listDevices().then((devices) => {
837
+ for (const listener of this.listeners) listener(devices);
838
+ });
839
+ }
840
+ emitPairingSessions() {
841
+ void this.listPairingSessions().then((sessions) => {
842
+ for (const listener of this.pairingListeners) listener(sessions);
843
+ });
844
+ }
845
+ };
846
+
847
+ // src/device-network/syncCloudDevices.ts
848
+ async function syncCloudDevices(input) {
849
+ const cloudDevices = await input.cloudClient.listDevices();
850
+ if (cloudDevices.length === 0) return [];
851
+ const existingRecords = await input.trustStore.loadTrustedDevices();
852
+ const existingByPeerId = new Map(existingRecords.map((r) => [r.peerId, r]));
853
+ for (const cloudDevice of cloudDevices) {
854
+ const existing = existingByPeerId.get(cloudDevice.peerId);
855
+ const record = {
856
+ peerId: cloudDevice.peerId,
857
+ publicKeyMultibase: cloudDevice.publicKeyMultibase,
858
+ deviceName: cloudDevice.deviceName,
859
+ platform: cloudDevice.platform,
860
+ trustMode: "cloud-account",
861
+ accountId: cloudDevice.accountId,
862
+ createdAt: existing?.createdAt ?? Date.now(),
863
+ lastSeen: cloudDevice.lastSeen,
864
+ revokedAt: cloudDevice.revokedAt
865
+ };
866
+ if (existing) {
867
+ existing.lastSeen = cloudDevice.lastSeen;
868
+ existing.revokedAt = cloudDevice.revokedAt;
869
+ if (existing.publicKeyMultibase !== record.publicKeyMultibase || existing.deviceName !== record.deviceName || existing.platform !== record.platform) {
870
+ await input.trustStore.saveTrustedDevice(record);
871
+ }
872
+ } else {
873
+ await input.trustStore.saveTrustedDevice(record);
874
+ }
875
+ }
876
+ return cloudDevices;
877
+ }
878
+ // Annotate the CommonJS export names for ESM import in node:
879
+ 0 && (module.exports = {
880
+ ChatSyncEngine,
881
+ DEVICE_ORCHESTRATION_PROTOCOL,
882
+ DEVICE_PAIRING_INVITE_PROTOCOL,
883
+ DEVICE_PAIRING_INVITE_TTL_MS,
884
+ LIBP2P_RPC_REQUEST_TYPE,
885
+ LIBP2P_RPC_RESPONSE_TYPE,
886
+ LIBP2P_SYNC_REQUEST_TYPE,
887
+ LIBP2P_SYNC_RESPONSE_TYPE,
888
+ Libp2pDeviceSyncTransport,
889
+ LocalTrustDeviceAuthorizer,
890
+ MemoryDeviceNetworkService,
891
+ PeerNodeSyncAdapter,
892
+ attachmentBlobFromWire,
893
+ createDeviceOrchestrationStreamHandler,
894
+ createDeviceOrchestrationTransport,
895
+ createDevicePairingInvite,
896
+ decodeAttachmentBlobRpc,
897
+ encodeDevicePairingInvite,
898
+ isConversationMeta,
899
+ isLibp2pRpcRequest,
900
+ isLibp2pRpcResponse,
901
+ isLibp2pSyncRequest,
902
+ isLibp2pSyncResponse,
903
+ parseDevicePairingInvite,
904
+ syncCloudDevices
905
+ });
906
+ //# sourceMappingURL=device-network.cjs.map