@opendatalabs/personal-server-ts-core 0.2.0 → 1.0.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 (340) hide show
  1. package/dist/api/index.d.ts +160 -0
  2. package/dist/api/index.d.ts.map +1 -0
  3. package/dist/api/index.js +774 -0
  4. package/dist/api/index.js.map +1 -0
  5. package/dist/auth/index.d.ts +2 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +2 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/auth/request.d.ts +28 -0
  10. package/dist/auth/request.d.ts.map +1 -0
  11. package/dist/auth/request.js +106 -0
  12. package/dist/auth/request.js.map +1 -0
  13. package/dist/client.d.ts +233 -0
  14. package/dist/client.d.ts.map +1 -0
  15. package/dist/client.js +243 -0
  16. package/dist/client.js.map +1 -0
  17. package/dist/config/defaults.d.ts +5 -5
  18. package/dist/config/defaults.d.ts.map +1 -1
  19. package/dist/config/defaults.js +3 -5
  20. package/dist/config/defaults.js.map +1 -1
  21. package/dist/config/index.d.ts +0 -1
  22. package/dist/config/index.d.ts.map +1 -1
  23. package/dist/config/index.js +0 -1
  24. package/dist/config/index.js.map +1 -1
  25. package/dist/config/paths.d.ts.map +1 -1
  26. package/dist/config/paths.js +1 -9
  27. package/dist/config/paths.js.map +1 -1
  28. package/dist/contracts/access-logs.d.ts +8 -0
  29. package/dist/contracts/access-logs.d.ts.map +1 -0
  30. package/dist/contracts/access-logs.js +7 -0
  31. package/dist/contracts/access-logs.js.map +1 -0
  32. package/dist/contracts/auth-device.d.ts +70 -0
  33. package/dist/contracts/auth-device.d.ts.map +1 -0
  34. package/dist/contracts/auth-device.js +163 -0
  35. package/dist/contracts/auth-device.js.map +1 -0
  36. package/dist/contracts/binary.d.ts +54 -0
  37. package/dist/contracts/binary.d.ts.map +1 -0
  38. package/dist/contracts/binary.js +92 -0
  39. package/dist/contracts/binary.js.map +1 -0
  40. package/dist/contracts/config.d.ts +5 -0
  41. package/dist/contracts/config.d.ts.map +1 -0
  42. package/dist/contracts/config.js +30 -0
  43. package/dist/contracts/config.js.map +1 -0
  44. package/dist/contracts/data.d.ts +115 -0
  45. package/dist/contracts/data.d.ts.map +1 -0
  46. package/dist/contracts/data.js +237 -0
  47. package/dist/contracts/data.js.map +1 -0
  48. package/dist/contracts/grants.d.ts +45 -0
  49. package/dist/contracts/grants.d.ts.map +1 -0
  50. package/dist/contracts/grants.js +177 -0
  51. package/dist/contracts/grants.js.map +1 -0
  52. package/dist/contracts/http.d.ts +21 -0
  53. package/dist/contracts/http.d.ts.map +1 -0
  54. package/dist/contracts/http.js +49 -0
  55. package/dist/contracts/http.js.map +1 -0
  56. package/dist/contracts/index.d.ts +16 -0
  57. package/dist/contracts/index.d.ts.map +1 -0
  58. package/dist/contracts/index.js +10 -0
  59. package/dist/contracts/index.js.map +1 -0
  60. package/dist/contracts/oauth.d.ts +38 -0
  61. package/dist/contracts/oauth.d.ts.map +1 -0
  62. package/dist/contracts/oauth.js +130 -0
  63. package/dist/contracts/oauth.js.map +1 -0
  64. package/dist/contracts/sync.d.ts +10 -0
  65. package/dist/contracts/sync.d.ts.map +1 -0
  66. package/dist/contracts/sync.js +34 -0
  67. package/dist/contracts/sync.js.map +1 -0
  68. package/dist/errors/catalog.d.ts +9 -0
  69. package/dist/errors/catalog.d.ts.map +1 -1
  70. package/dist/errors/catalog.js +15 -0
  71. package/dist/errors/catalog.js.map +1 -1
  72. package/dist/grants/index.d.ts +2 -4
  73. package/dist/grants/index.d.ts.map +1 -1
  74. package/dist/grants/index.js +1 -2
  75. package/dist/grants/index.js.map +1 -1
  76. package/dist/keys/index.d.ts +1 -2
  77. package/dist/keys/index.d.ts.map +1 -1
  78. package/dist/keys/index.js +1 -2
  79. package/dist/keys/index.js.map +1 -1
  80. package/dist/keys/server-account.d.ts +5 -9
  81. package/dist/keys/server-account.d.ts.map +1 -1
  82. package/dist/keys/server-account.js +1 -47
  83. package/dist/keys/server-account.js.map +1 -1
  84. package/dist/logger/index.d.ts +6 -2
  85. package/dist/logger/index.d.ts.map +1 -1
  86. package/dist/logger/index.js +2 -6
  87. package/dist/logger/index.js.map +1 -1
  88. package/dist/logging/access-log.d.ts +0 -1
  89. package/dist/logging/access-log.d.ts.map +1 -1
  90. package/dist/logging/access-log.js +1 -24
  91. package/dist/logging/access-log.js.map +1 -1
  92. package/dist/logging/access-reader.d.ts +0 -5
  93. package/dist/logging/access-reader.d.ts.map +1 -1
  94. package/dist/logging/access-reader.js +1 -49
  95. package/dist/logging/access-reader.js.map +1 -1
  96. package/dist/mcp/activity.d.ts +68 -0
  97. package/dist/mcp/activity.d.ts.map +1 -0
  98. package/dist/mcp/activity.js +111 -0
  99. package/dist/mcp/activity.js.map +1 -0
  100. package/dist/mcp/builder-registration.d.ts +24 -0
  101. package/dist/mcp/builder-registration.d.ts.map +1 -0
  102. package/dist/mcp/builder-registration.js +89 -0
  103. package/dist/mcp/builder-registration.js.map +1 -0
  104. package/dist/mcp/connection-api.d.ts +170 -0
  105. package/dist/mcp/connection-api.d.ts.map +1 -0
  106. package/dist/mcp/connection-api.js +379 -0
  107. package/dist/mcp/connection-api.js.map +1 -0
  108. package/dist/mcp/grantee.d.ts +52 -0
  109. package/dist/mcp/grantee.d.ts.map +1 -0
  110. package/dist/mcp/grantee.js +91 -0
  111. package/dist/mcp/grantee.js.map +1 -0
  112. package/dist/mcp/index.d.ts +10 -0
  113. package/dist/mcp/index.d.ts.map +1 -0
  114. package/dist/mcp/index.js +10 -0
  115. package/dist/mcp/index.js.map +1 -0
  116. package/dist/mcp/read-client.d.ts +136 -0
  117. package/dist/mcp/read-client.d.ts.map +1 -0
  118. package/dist/mcp/read-client.js +306 -0
  119. package/dist/mcp/read-client.js.map +1 -0
  120. package/dist/mcp/resources.d.ts +37 -0
  121. package/dist/mcp/resources.d.ts.map +1 -0
  122. package/dist/mcp/resources.js +114 -0
  123. package/dist/mcp/resources.js.map +1 -0
  124. package/dist/mcp/search/index.d.ts +34 -0
  125. package/dist/mcp/search/index.d.ts.map +1 -0
  126. package/dist/mcp/search/index.js +69 -0
  127. package/dist/mcp/search/index.js.map +1 -0
  128. package/dist/mcp/server.d.ts +53 -0
  129. package/dist/mcp/server.d.ts.map +1 -0
  130. package/dist/mcp/server.js +308 -0
  131. package/dist/mcp/server.js.map +1 -0
  132. package/dist/mcp/store.d.ts +13 -0
  133. package/dist/mcp/store.d.ts.map +1 -0
  134. package/dist/mcp/store.js +98 -0
  135. package/dist/mcp/store.js.map +1 -0
  136. package/dist/mcp/tools.d.ts +60 -0
  137. package/dist/mcp/tools.d.ts.map +1 -0
  138. package/dist/mcp/tools.js +1058 -0
  139. package/dist/mcp/tools.js.map +1 -0
  140. package/dist/mcp/types.d.ts +97 -0
  141. package/dist/mcp/types.d.ts.map +1 -0
  142. package/dist/mcp/types.js +24 -0
  143. package/dist/mcp/types.js.map +1 -0
  144. package/dist/payment/index.d.ts +2 -0
  145. package/dist/payment/index.d.ts.map +1 -0
  146. package/dist/payment/index.js +2 -0
  147. package/dist/payment/index.js.map +1 -0
  148. package/dist/payment/x402.d.ts +155 -0
  149. package/dist/payment/x402.d.ts.map +1 -0
  150. package/dist/payment/x402.js +402 -0
  151. package/dist/payment/x402.js.map +1 -0
  152. package/dist/policy/data-read.d.ts +15 -0
  153. package/dist/policy/data-read.d.ts.map +1 -0
  154. package/dist/policy/data-read.js +84 -0
  155. package/dist/policy/data-read.js.map +1 -0
  156. package/dist/policy/index.d.ts +2 -0
  157. package/dist/policy/index.d.ts.map +1 -0
  158. package/dist/policy/index.js +2 -0
  159. package/dist/policy/index.js.map +1 -0
  160. package/dist/ports/index.d.ts +95 -0
  161. package/dist/ports/index.d.ts.map +1 -0
  162. package/dist/ports/index.js +7 -0
  163. package/dist/ports/index.js.map +1 -0
  164. package/dist/schemas/server-config.d.ts +12 -0
  165. package/dist/schemas/server-config.d.ts.map +1 -1
  166. package/dist/schemas/server-config.js +34 -4
  167. package/dist/schemas/server-config.js.map +1 -1
  168. package/dist/signing/index.d.ts +0 -1
  169. package/dist/signing/index.d.ts.map +1 -1
  170. package/dist/signing/index.js +0 -1
  171. package/dist/signing/index.js.map +1 -1
  172. package/dist/signing/request-signer.d.ts +8 -2
  173. package/dist/signing/request-signer.d.ts.map +1 -1
  174. package/dist/signing/request-signer.js +5 -31
  175. package/dist/signing/request-signer.js.map +1 -1
  176. package/dist/signing/signer.d.ts +20 -2
  177. package/dist/signing/signer.d.ts.map +1 -1
  178. package/dist/signing/signer.js +23 -13
  179. package/dist/signing/signer.js.map +1 -1
  180. package/dist/storage/adapters/index.d.ts +2 -1
  181. package/dist/storage/adapters/index.d.ts.map +1 -1
  182. package/dist/storage/adapters/index.js +2 -1
  183. package/dist/storage/adapters/index.js.map +1 -1
  184. package/dist/storage/adapters/interface.d.ts +10 -0
  185. package/dist/storage/adapters/interface.d.ts.map +1 -1
  186. package/dist/storage/adapters/sdk.d.ts +23 -0
  187. package/dist/storage/adapters/sdk.d.ts.map +1 -0
  188. package/dist/storage/adapters/sdk.js +73 -0
  189. package/dist/storage/adapters/sdk.js.map +1 -0
  190. package/dist/storage/adapters/vana.d.ts +7 -30
  191. package/dist/storage/adapters/vana.d.ts.map +1 -1
  192. package/dist/storage/adapters/vana.js +37 -92
  193. package/dist/storage/adapters/vana.js.map +1 -1
  194. package/dist/storage/blocks/build.d.ts +20 -0
  195. package/dist/storage/blocks/build.d.ts.map +1 -0
  196. package/dist/storage/blocks/build.js +378 -0
  197. package/dist/storage/blocks/build.js.map +1 -0
  198. package/dist/storage/blocks/cursor.d.ts +33 -0
  199. package/dist/storage/blocks/cursor.d.ts.map +1 -0
  200. package/dist/storage/blocks/cursor.js +142 -0
  201. package/dist/storage/blocks/cursor.js.map +1 -0
  202. package/dist/storage/blocks/errors.d.ts +6 -0
  203. package/dist/storage/blocks/errors.d.ts.map +1 -0
  204. package/dist/storage/blocks/errors.js +9 -0
  205. package/dist/storage/blocks/errors.js.map +1 -0
  206. package/dist/storage/blocks/index.d.ts +5 -0
  207. package/dist/storage/blocks/index.d.ts.map +1 -0
  208. package/dist/storage/blocks/index.js +4 -0
  209. package/dist/storage/blocks/index.js.map +1 -0
  210. package/dist/storage/blocks/types.d.ts +49 -0
  211. package/dist/storage/blocks/types.d.ts.map +1 -0
  212. package/dist/storage/blocks/types.js +2 -0
  213. package/dist/{grants → storage/blocks}/types.js.map +1 -1
  214. package/dist/storage/hierarchy/index.d.ts +0 -1
  215. package/dist/storage/hierarchy/index.d.ts.map +1 -1
  216. package/dist/storage/hierarchy/index.js +0 -1
  217. package/dist/storage/hierarchy/index.js.map +1 -1
  218. package/dist/storage/hierarchy/manager.d.ts +0 -14
  219. package/dist/storage/hierarchy/manager.d.ts.map +1 -1
  220. package/dist/storage/hierarchy/manager.js +1 -59
  221. package/dist/storage/hierarchy/manager.js.map +1 -1
  222. package/dist/storage/hierarchy/paths.d.ts.map +1 -1
  223. package/dist/storage/hierarchy/paths.js +11 -4
  224. package/dist/storage/hierarchy/paths.js.map +1 -1
  225. package/dist/storage/index/index.d.ts +2 -3
  226. package/dist/storage/index/index.d.ts.map +1 -1
  227. package/dist/storage/index/index.js +1 -2
  228. package/dist/storage/index/index.js.map +1 -1
  229. package/dist/storage/index/manager.d.ts +26 -6
  230. package/dist/storage/index/manager.d.ts.map +1 -1
  231. package/dist/storage/index/manager.js +1 -131
  232. package/dist/storage/index/manager.js.map +1 -1
  233. package/dist/storage/index/schema.d.ts +1 -3
  234. package/dist/storage/index/schema.d.ts.map +1 -1
  235. package/dist/storage/index/schema.js +1 -26
  236. package/dist/storage/index/schema.js.map +1 -1
  237. package/dist/storage/index/types.d.ts +16 -0
  238. package/dist/storage/index/types.d.ts.map +1 -1
  239. package/dist/storage/preview.d.ts +12 -0
  240. package/dist/storage/preview.d.ts.map +1 -0
  241. package/dist/storage/preview.js +239 -0
  242. package/dist/storage/preview.js.map +1 -0
  243. package/dist/sync/cursor.d.ts +5 -7
  244. package/dist/sync/cursor.d.ts.map +1 -1
  245. package/dist/sync/cursor.js +1 -18
  246. package/dist/sync/cursor.js.map +1 -1
  247. package/dist/sync/engine/sync-manager.d.ts +17 -0
  248. package/dist/sync/engine/sync-manager.d.ts.map +1 -1
  249. package/dist/sync/engine/sync-manager.js +104 -43
  250. package/dist/sync/engine/sync-manager.js.map +1 -1
  251. package/dist/sync/index.d.ts +4 -2
  252. package/dist/sync/index.d.ts.map +1 -1
  253. package/dist/sync/index.js +1 -1
  254. package/dist/sync/index.js.map +1 -1
  255. package/dist/sync/issues.d.ts +55 -0
  256. package/dist/sync/issues.d.ts.map +1 -0
  257. package/dist/sync/issues.js +168 -0
  258. package/dist/sync/issues.js.map +1 -0
  259. package/dist/sync/retry-memory.d.ts +33 -0
  260. package/dist/sync/retry-memory.d.ts.map +1 -0
  261. package/dist/sync/retry-memory.js +68 -0
  262. package/dist/sync/retry-memory.js.map +1 -0
  263. package/dist/sync/types.d.ts +9 -24
  264. package/dist/sync/types.d.ts.map +1 -1
  265. package/dist/sync/workers/delete.d.ts +42 -0
  266. package/dist/sync/workers/delete.d.ts.map +1 -0
  267. package/dist/sync/workers/delete.js +40 -0
  268. package/dist/sync/workers/delete.js.map +1 -0
  269. package/dist/sync/workers/download.d.ts +64 -18
  270. package/dist/sync/workers/download.d.ts.map +1 -1
  271. package/dist/sync/workers/download.js +396 -54
  272. package/dist/sync/workers/download.js.map +1 -1
  273. package/dist/sync/workers/upload.d.ts +29 -18
  274. package/dist/sync/workers/upload.d.ts.map +1 -1
  275. package/dist/sync/workers/upload.js +163 -46
  276. package/dist/sync/workers/upload.js.map +1 -1
  277. package/dist/test-utils/wallet.d.ts +1 -0
  278. package/dist/test-utils/wallet.d.ts.map +1 -1
  279. package/dist/test-utils/wallet.js +9 -31
  280. package/dist/test-utils/wallet.js.map +1 -1
  281. package/package.json +51 -27
  282. package/dist/auth/web3-signed.d.ts +0 -48
  283. package/dist/auth/web3-signed.d.ts.map +0 -1
  284. package/dist/auth/web3-signed.js +0 -110
  285. package/dist/auth/web3-signed.js.map +0 -1
  286. package/dist/config/loader.d.ts +0 -8
  287. package/dist/config/loader.d.ts.map +0 -1
  288. package/dist/config/loader.js +0 -38
  289. package/dist/config/loader.js.map +0 -1
  290. package/dist/gateway/client.d.ts +0 -98
  291. package/dist/gateway/client.d.ts.map +0 -1
  292. package/dist/gateway/client.js +0 -171
  293. package/dist/gateway/client.js.map +0 -1
  294. package/dist/grants/eip712.d.ts +0 -28
  295. package/dist/grants/eip712.d.ts.map +0 -1
  296. package/dist/grants/eip712.js +0 -30
  297. package/dist/grants/eip712.js.map +0 -1
  298. package/dist/grants/types.d.ts +0 -29
  299. package/dist/grants/types.d.ts.map +0 -1
  300. package/dist/grants/types.js +0 -6
  301. package/dist/grants/verify.d.ts +0 -24
  302. package/dist/grants/verify.d.ts.map +0 -1
  303. package/dist/grants/verify.js +0 -71
  304. package/dist/grants/verify.js.map +0 -1
  305. package/dist/keys/derive.d.ts +0 -18
  306. package/dist/keys/derive.d.ts.map +0 -1
  307. package/dist/keys/derive.js +0 -43
  308. package/dist/keys/derive.js.map +0 -1
  309. package/dist/schemas/data-file.d.ts +0 -20
  310. package/dist/schemas/data-file.d.ts.map +0 -1
  311. package/dist/schemas/data-file.js +0 -23
  312. package/dist/schemas/data-file.js.map +0 -1
  313. package/dist/scopes/index.d.ts +0 -3
  314. package/dist/scopes/index.d.ts.map +0 -1
  315. package/dist/scopes/index.js +0 -3
  316. package/dist/scopes/index.js.map +0 -1
  317. package/dist/scopes/match.d.ts +0 -13
  318. package/dist/scopes/match.d.ts.map +0 -1
  319. package/dist/scopes/match.js +0 -23
  320. package/dist/scopes/match.js.map +0 -1
  321. package/dist/scopes/parse.d.ts +0 -12
  322. package/dist/scopes/parse.d.ts.map +0 -1
  323. package/dist/scopes/parse.js +0 -29
  324. package/dist/scopes/parse.js.map +0 -1
  325. package/dist/signing/eip712.d.ts +0 -69
  326. package/dist/signing/eip712.d.ts.map +0 -1
  327. package/dist/signing/eip712.js +0 -68
  328. package/dist/signing/eip712.js.map +0 -1
  329. package/dist/storage/encryption/decrypt.d.ts +0 -10
  330. package/dist/storage/encryption/decrypt.d.ts.map +0 -1
  331. package/dist/storage/encryption/decrypt.js +0 -19
  332. package/dist/storage/encryption/decrypt.js.map +0 -1
  333. package/dist/storage/encryption/encrypt.d.ts +0 -10
  334. package/dist/storage/encryption/encrypt.d.ts.map +0 -1
  335. package/dist/storage/encryption/encrypt.js +0 -19
  336. package/dist/storage/encryption/encrypt.js.map +0 -1
  337. package/dist/storage/encryption/index.d.ts +0 -3
  338. package/dist/storage/encryption/index.d.ts.map +0 -1
  339. package/dist/storage/encryption/index.js +0 -3
  340. package/dist/storage/encryption/index.js.map +0 -1
@@ -1,61 +1,96 @@
1
1
  import { uploadAll } from "../workers/upload.js";
2
2
  import { downloadAll } from "../workers/download.js";
3
+ import { deleteScopeRemote } from "../workers/delete.js";
4
+ import { createDownloadRetryMemory } from "../retry-memory.js";
3
5
  const MAX_ERRORS = 10;
4
6
  export function createSyncManager(uploadDeps, downloadDeps, options) {
5
7
  const pollInterval = options?.pollInterval ?? 60_000;
6
8
  const uploadBatchSize = options?.uploadBatchSize ?? 50;
9
+ const notifyDebounceMs = options?.notifyDebounceMs ?? 500;
7
10
  let intervalId = null;
11
+ let notifyTimerId = null;
8
12
  let isRunning = false;
9
13
  let lastSync = null;
10
14
  let lastProcessedTimestamp = null;
15
+ let blocked = null;
11
16
  let errors = [];
12
17
  let cycleInFlight = null;
18
+ let rerunRequested = false;
19
+ let needsFullReconcile = true;
20
+ // One retry memory per manager (= per boot session): a blob that 404s is
21
+ // attempted once per session, not once per cycle; transient storage errors
22
+ // back off exponentially instead of re-firing on every cycle.
23
+ const downloadRetryMemory = createDownloadRetryMemory();
13
24
  async function runCycle() {
14
25
  // Prevent concurrent cycles
15
26
  if (cycleInFlight) {
27
+ rerunRequested = true;
16
28
  return cycleInFlight;
17
29
  }
18
30
  cycleInFlight = (async () => {
19
- try {
20
- // Upload unsynced local files
21
- const uploadResults = await uploadAll(uploadDeps, {
22
- batchSize: uploadBatchSize,
23
- });
24
- uploadDeps.logger.debug({ uploaded: uploadResults.length }, "Upload cycle complete");
25
- }
26
- catch (err) {
27
- const syncError = {
28
- fileId: null,
29
- scope: null,
30
- message: `Upload cycle failed: ${err.message}`,
31
- timestamp: new Date().toISOString(),
32
- };
33
- pushError(syncError);
34
- uploadDeps.logger.error({ error: err.message }, "Upload cycle failed");
35
- }
36
- try {
37
- // Download new remote files
38
- const downloadResults = await downloadAll(downloadDeps);
39
- downloadDeps.logger.debug({ downloaded: downloadResults.length }, "Download cycle complete");
40
- }
41
- catch (err) {
42
- const syncError = {
43
- fileId: null,
44
- scope: null,
45
- message: `Download cycle failed: ${err.message}`,
46
- timestamp: new Date().toISOString(),
47
- };
48
- pushError(syncError);
49
- downloadDeps.logger.error({ error: err.message }, "Download cycle failed");
50
- }
51
- // Update cached cursor value
52
- try {
53
- lastProcessedTimestamp = await downloadDeps.cursor.read();
54
- }
55
- catch {
56
- // Non-critical: status will show stale value
57
- }
58
- lastSync = new Date().toISOString();
31
+ do {
32
+ rerunRequested = false;
33
+ const canRun = await (options?.canSync?.() ?? { ok: true });
34
+ if (!canRun.ok) {
35
+ blocked = { reason: canRun.reason, message: canRun.message };
36
+ uploadDeps.logger.warn(blocked, "Sync cycle blocked");
37
+ continue;
38
+ }
39
+ blocked = null;
40
+ try {
41
+ // Upload unsynced local files
42
+ const uploadResults = await uploadAll(uploadDeps, {
43
+ batchSize: uploadBatchSize,
44
+ onError(entry, error) {
45
+ pushError({
46
+ fileId: entry.fileId,
47
+ scope: entry.scope,
48
+ message: `Upload failed for ${entry.path}: ${error.message}`,
49
+ timestamp: new Date().toISOString(),
50
+ });
51
+ },
52
+ });
53
+ uploadDeps.logger.debug({ uploaded: uploadResults.length }, "Upload cycle complete");
54
+ }
55
+ catch (err) {
56
+ const syncError = {
57
+ fileId: null,
58
+ scope: null,
59
+ message: `Upload cycle failed: ${err.message}`,
60
+ timestamp: new Date().toISOString(),
61
+ };
62
+ pushError(syncError);
63
+ uploadDeps.logger.error({ error: err.message }, "Upload cycle failed");
64
+ }
65
+ try {
66
+ // Download new remote files
67
+ const fullReconcile = needsFullReconcile;
68
+ const downloadResults = await downloadAll(downloadDeps, {
69
+ fullReconcile,
70
+ retryMemory: downloadRetryMemory,
71
+ });
72
+ needsFullReconcile = false;
73
+ downloadDeps.logger.debug({ downloaded: downloadResults.length, fullReconcile }, "Download cycle complete");
74
+ }
75
+ catch (err) {
76
+ const syncError = {
77
+ fileId: null,
78
+ scope: null,
79
+ message: `Download cycle failed: ${err.message}`,
80
+ timestamp: new Date().toISOString(),
81
+ };
82
+ pushError(syncError);
83
+ downloadDeps.logger.error({ error: err.message }, "Download cycle failed");
84
+ }
85
+ // Update cached cursor value
86
+ try {
87
+ lastProcessedTimestamp = await downloadDeps.cursor.read();
88
+ }
89
+ catch {
90
+ // Non-critical: status will show stale value
91
+ }
92
+ lastSync = new Date().toISOString();
93
+ } while (rerunRequested && isRunning);
59
94
  })();
60
95
  try {
61
96
  await cycleInFlight;
@@ -64,6 +99,18 @@ export function createSyncManager(uploadDeps, downloadDeps, options) {
64
99
  cycleInFlight = null;
65
100
  }
66
101
  }
102
+ function scheduleNotifiedCycle() {
103
+ if (!isRunning || notifyTimerId !== null)
104
+ return;
105
+ notifyTimerId = setTimeout(() => {
106
+ notifyTimerId = null;
107
+ if (!isRunning)
108
+ return;
109
+ runCycle().catch(() => {
110
+ // Errors already captured in ring buffer
111
+ });
112
+ }, notifyDebounceMs);
113
+ }
67
114
  function pushError(error) {
68
115
  errors.push(error);
69
116
  if (errors.length > MAX_ERRORS) {
@@ -85,6 +132,12 @@ export function createSyncManager(uploadDeps, downloadDeps, options) {
85
132
  intervalId = null;
86
133
  }
87
134
  }
135
+ function clearNotifyTimer() {
136
+ if (notifyTimerId !== null) {
137
+ clearTimeout(notifyTimerId);
138
+ notifyTimerId = null;
139
+ }
140
+ }
88
141
  const manager = {
89
142
  get running() {
90
143
  return isRunning;
@@ -101,6 +154,7 @@ export function createSyncManager(uploadDeps, downloadDeps, options) {
101
154
  },
102
155
  async stop() {
103
156
  clearIntervalTimer();
157
+ clearNotifyTimer();
104
158
  isRunning = false;
105
159
  // Wait for any in-flight cycle to complete
106
160
  if (cycleInFlight) {
@@ -108,18 +162,21 @@ export function createSyncManager(uploadDeps, downloadDeps, options) {
108
162
  }
109
163
  },
110
164
  async trigger() {
111
- // Clear existing interval, run immediately, restart interval
165
+ // Clear existing timers, run immediately, restart interval
112
166
  clearIntervalTimer();
167
+ clearNotifyTimer();
113
168
  await runCycle();
114
169
  if (isRunning) {
115
170
  startInterval();
116
171
  }
117
172
  },
118
173
  getStatus() {
119
- const pendingFiles = uploadDeps.indexManager.findUnsynced().length;
174
+ const pendingFiles = uploadDeps.storage.findUnsynced().length;
120
175
  return {
121
176
  enabled: true,
122
177
  running: isRunning,
178
+ syncing: cycleInFlight !== null,
179
+ blocked,
123
180
  lastSync,
124
181
  lastProcessedTimestamp,
125
182
  pendingFiles,
@@ -127,8 +184,12 @@ export function createSyncManager(uploadDeps, downloadDeps, options) {
127
184
  };
128
185
  },
129
186
  notifyNewData() {
130
- // No-op signal — the next cycle picks up unsynced entries automatically.
131
187
  uploadDeps.logger.debug("New data notification received");
188
+ scheduleNotifiedCycle();
189
+ },
190
+ async deleteScopeRemote(scope) {
191
+ // Reuses the upload worker's remote deps (gateway, storage adapter, signer, owner).
192
+ await deleteScopeRemote(uploadDeps, scope);
132
193
  },
133
194
  };
134
195
  return manager;
@@ -1 +1 @@
1
- {"version":3,"file":"sync-manager.js","sourceRoot":"","sources":["../../../src/sync/engine/sync-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-manager.js","sourceRoot":"","sources":["../../../src/sync/engine/sync-manager.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
- export type { FileRecord, FileListResult, RegisterFileParams, FileRegistration, SyncStatus, SyncError, } from "./types.js";
2
- export { createSyncCursor, type SyncCursor } from "./cursor.js";
1
+ export type { SyncStatus, SyncError } from "./types.js";
2
+ export type { SyncCursor } from "./cursor.js";
3
+ export { classifySyncFailure, inferPayloadKind, type ClassifiedSyncFailure, type ClassifySyncFailureInput, type SyncDownloadFailureTelemetryEvent, type SyncFailureDisposition, type SyncFailureStage, type SyncFileIssue, type SyncPayloadKind, } from "./issues.js";
3
4
  export { createSyncManager, type SyncManager, type SyncManagerOptions, } from "./engine/sync-manager.js";
5
+ export type { DownloadDiagnosticsHook, DownloadWorkerDeps, } from "./workers/download.js";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACV,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EACtC,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC"}
@@ -1,3 +1,3 @@
1
- export { createSyncCursor } from "./cursor.js";
1
+ export { classifySyncFailure, inferPayloadKind, } from "./issues.js";
2
2
  export { createSyncManager, } from "./engine/sync-manager.js";
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAmB,MAAM,aAAa,CAAC;AAChE,OAAO,EACL,iBAAiB,GAGlB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAQjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,GAGlB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,55 @@
1
+ export type SyncFailureStage = "download" | "openpgp_parse" | "decrypt" | "json_parse" | "envelope_validate" | "block_build" | "unknown";
2
+ export type SyncPayloadKind = "openpgp" | "json" | "html" | "empty" | "binary" | "unknown";
3
+ export type SyncFailureDisposition = "deterministic" | "transient";
4
+ export interface SyncFileIssue {
5
+ fileId: string;
6
+ schemaId?: string;
7
+ scope?: string;
8
+ stage: SyncFailureStage;
9
+ errorClass: string;
10
+ message: string;
11
+ payloadKind?: SyncPayloadKind;
12
+ encryptedSizeBytes?: number;
13
+ syncRunId: string;
14
+ firstSeenAt: string;
15
+ lastSeenAt: string;
16
+ disposition: SyncFailureDisposition;
17
+ retryable: boolean;
18
+ }
19
+ export interface SyncDownloadFailureTelemetryEvent {
20
+ event: "sync.download.failure";
21
+ syncRunId: string;
22
+ fileId: string;
23
+ schemaId?: string;
24
+ scope?: string;
25
+ stage: SyncFailureStage;
26
+ payloadKind?: SyncPayloadKind;
27
+ encryptedSizeBytes?: number;
28
+ errorClass: string;
29
+ disposition: SyncFailureDisposition;
30
+ retryable: boolean;
31
+ appVersion?: string;
32
+ personalServerVersion?: string;
33
+ storageBackend?: string;
34
+ }
35
+ export interface ClassifySyncFailureInput {
36
+ error: unknown;
37
+ fileId: string;
38
+ syncRunId: string;
39
+ stage?: SyncFailureStage;
40
+ schemaId?: string;
41
+ scope?: string;
42
+ payloadKind?: SyncPayloadKind;
43
+ encryptedSizeBytes?: number;
44
+ now?: Date;
45
+ appVersion?: string;
46
+ personalServerVersion?: string;
47
+ storageBackend?: string;
48
+ }
49
+ export interface ClassifiedSyncFailure {
50
+ issue: SyncFileIssue;
51
+ telemetry: SyncDownloadFailureTelemetryEvent;
52
+ }
53
+ export declare function classifySyncFailure(input: ClassifySyncFailureInput): ClassifiedSyncFailure;
54
+ export declare function inferPayloadKind(bytes: Uint8Array | string): SyncPayloadKind;
55
+ //# sourceMappingURL=issues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/sync/issues.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,eAAe,GACf,SAAS,GACT,YAAY,GACZ,mBAAmB,GACnB,aAAa,GACb,SAAS,CAAC;AAEd,MAAM,MAAM,eAAe,GACzB,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG,WAAW,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,gBAAgB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,sBAAsB,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,KAAK,EAAE,uBAAuB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,sBAAsB,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,iCAAiC,CAAC;CAC9C;AAiBD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,qBAAqB,CA0CvB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,eAAe,CAgB5E"}
@@ -0,0 +1,168 @@
1
+ const DETERMINISTIC_STAGES = new Set([
2
+ "openpgp_parse",
3
+ "decrypt",
4
+ "json_parse",
5
+ "envelope_validate",
6
+ "block_build",
7
+ ]);
8
+ // Only statuses that PROVE the blob cannot appear by retrying are
9
+ // deterministic. Everything else — 5xx, Cloudflare 52x, 401/403 auth blips
10
+ // (downloads are Web3Signed off the local clock), 429 — is treated as
11
+ // transient and bounded by the retry memory's attempt cap instead of being
12
+ // permanently quarantined on first sight.
13
+ const DETERMINISTIC_DOWNLOAD_STATUSES = new Set([404, 410]);
14
+ export function classifySyncFailure(input) {
15
+ const stage = input.stage ?? inferStage(input.error);
16
+ const disposition = classifyDisposition(input.error, stage);
17
+ const retryable = disposition === "transient";
18
+ const timestamp = (input.now ?? new Date()).toISOString();
19
+ const errorClass = getErrorClass(input.error);
20
+ const message = getSafeIssueMessage(stage, disposition);
21
+ const issue = {
22
+ fileId: input.fileId,
23
+ schemaId: input.schemaId,
24
+ scope: input.scope,
25
+ stage,
26
+ errorClass,
27
+ message,
28
+ payloadKind: input.payloadKind,
29
+ encryptedSizeBytes: input.encryptedSizeBytes,
30
+ syncRunId: input.syncRunId,
31
+ firstSeenAt: timestamp,
32
+ lastSeenAt: timestamp,
33
+ disposition,
34
+ retryable,
35
+ };
36
+ const telemetry = {
37
+ event: "sync.download.failure",
38
+ syncRunId: input.syncRunId,
39
+ fileId: input.fileId,
40
+ schemaId: input.schemaId,
41
+ scope: input.scope,
42
+ stage,
43
+ payloadKind: input.payloadKind,
44
+ encryptedSizeBytes: input.encryptedSizeBytes,
45
+ errorClass,
46
+ disposition,
47
+ retryable,
48
+ appVersion: input.appVersion,
49
+ personalServerVersion: input.personalServerVersion,
50
+ storageBackend: input.storageBackend,
51
+ };
52
+ return { issue, telemetry };
53
+ }
54
+ export function inferPayloadKind(bytes) {
55
+ const text = typeof bytes === "string"
56
+ ? bytes
57
+ : new TextDecoder().decode(bytes.slice(0, 256));
58
+ const trimmed = text.trimStart();
59
+ if (trimmed.length === 0)
60
+ return "empty";
61
+ if (trimmed.startsWith("-----BEGIN PGP MESSAGE-----"))
62
+ return "openpgp";
63
+ if (trimmed.startsWith("{") || trimmed.startsWith("["))
64
+ return "json";
65
+ if (/^<!doctype html\b/i.test(trimmed) || /^<html[\s>]/i.test(trimmed)) {
66
+ return "html";
67
+ }
68
+ if (containsBinaryByte(bytes))
69
+ return "binary";
70
+ return "unknown";
71
+ }
72
+ function classifyDisposition(error, stage) {
73
+ if (stage === "download") {
74
+ const status = getNumericProperty(error, "status") ??
75
+ getNumericProperty(error, "statusCode") ??
76
+ getDownloadStatusFromMessage(error);
77
+ if (status !== undefined) {
78
+ return DETERMINISTIC_DOWNLOAD_STATUSES.has(status)
79
+ ? "deterministic"
80
+ : "transient";
81
+ }
82
+ return "transient";
83
+ }
84
+ if (DETERMINISTIC_STAGES.has(stage)) {
85
+ return "deterministic";
86
+ }
87
+ return "transient";
88
+ }
89
+ function inferStage(error) {
90
+ if (error instanceof SyntaxError)
91
+ return "json_parse";
92
+ const name = getStringProperty(error, "name").toLowerCase();
93
+ const message = getRawMessage(error).toLowerCase();
94
+ if (name === "zoderror" || message.includes("zod"))
95
+ return "envelope_validate";
96
+ if (message.includes("decrypt") || message.includes("session key"))
97
+ return "decrypt";
98
+ if (message.includes("openpgp") || message.includes("pgp message")) {
99
+ return "openpgp_parse";
100
+ }
101
+ return "unknown";
102
+ }
103
+ function getErrorClass(error) {
104
+ const name = getStringProperty(error, "name");
105
+ if (name.length > 0)
106
+ return name;
107
+ if (error instanceof Error && error.constructor.name.length > 0) {
108
+ return error.constructor.name;
109
+ }
110
+ return typeof error;
111
+ }
112
+ function getRawMessage(error) {
113
+ if (error instanceof Error)
114
+ return error.message;
115
+ if (typeof error === "string")
116
+ return error;
117
+ const message = getStringProperty(error, "message");
118
+ return message.length > 0 ? message : "Unknown sync failure";
119
+ }
120
+ function getStringProperty(value, key) {
121
+ if (typeof value !== "object" || value === null || !(key in value))
122
+ return "";
123
+ const property = value[key];
124
+ return typeof property === "string" ? property : "";
125
+ }
126
+ // The SDK's StorageError carries the HTTP status only in its message —
127
+ // "vana-storage download failed: 404 Not Found" — with no numeric property.
128
+ // Without this fallback a 404'd blob classifies transient and is retried
129
+ // every sync cycle forever. The anchored "download failed: " prefix mirrors
130
+ // the provider's stable message shape and avoids misreading digits in
131
+ // network-error causes (IPs, ports), which stay transient.
132
+ function getDownloadStatusFromMessage(error) {
133
+ const match = /download failed: ([1-5]\d{2})\b/.exec(getRawMessage(error));
134
+ return match ? Number(match[1]) : undefined;
135
+ }
136
+ function getNumericProperty(value, key) {
137
+ if (typeof value !== "object" || value === null || !(key in value)) {
138
+ return undefined;
139
+ }
140
+ const property = value[key];
141
+ return typeof property === "number" ? property : undefined;
142
+ }
143
+ function containsBinaryByte(bytes) {
144
+ if (typeof bytes === "string")
145
+ return false;
146
+ return bytes.some((byte) => byte === 0 || (byte < 0x09 && byte !== 0x07));
147
+ }
148
+ function getSafeIssueMessage(stage, disposition) {
149
+ switch (stage) {
150
+ case "download":
151
+ return disposition === "transient"
152
+ ? "Download failed with a retryable storage or network error"
153
+ : "Download failed with a non-retryable storage response";
154
+ case "openpgp_parse":
155
+ return "Encrypted payload could not be parsed as an OpenPGP message";
156
+ case "decrypt":
157
+ return "Encrypted payload could not be decrypted";
158
+ case "json_parse":
159
+ return "Decrypted payload could not be parsed as JSON";
160
+ case "envelope_validate":
161
+ return "Decrypted JSON did not match the expected envelope shape";
162
+ case "block_build":
163
+ return "Envelope was stored, but bounded block build failed";
164
+ case "unknown":
165
+ return "Sync file failed at an unknown stage";
166
+ }
167
+ }
168
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/sync/issues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export type DownloadAttemptDecision = "attempt" | "backoff" | "give-up";
2
+ export interface DownloadRetryMemoryOptions {
3
+ /** Attempt cap for retryable failures (default 5). */
4
+ maxTransientAttempts?: number;
5
+ /** Base backoff, doubled per failed attempt (default 30s). */
6
+ backoffBaseMs?: number;
7
+ /** Clock override for tests. */
8
+ now?: () => number;
9
+ }
10
+ export declare const DEFAULT_MAX_TRANSIENT_ATTEMPTS = 5;
11
+ export declare const DEFAULT_BACKOFF_BASE_MS = 30000;
12
+ export interface DownloadRetryMemory {
13
+ /** Whether the next download of `key` should run, wait, or never happen. */
14
+ decide(key: string): DownloadAttemptDecision;
15
+ /** Record a failed attempt; `retryable` follows the issue classification. */
16
+ recordFailure(key: string, retryable: boolean): void;
17
+ /** Clear the failure history after a successful download. */
18
+ recordSuccess(key: string): void;
19
+ /**
20
+ * The listing restarted from the beginning (repair pass / full
21
+ * reconcile) — give transient failures a fresh attempt budget so the
22
+ * reset can actually re-fetch what it re-lists. Deterministic (404)
23
+ * entries stay dead: re-listing doesn't make missing bytes appear.
24
+ */
25
+ onListingReset(): void;
26
+ }
27
+ /** Retry-memory key for a data-point record: id + version. */
28
+ export declare function downloadRetryKey(record: {
29
+ id: string;
30
+ expectedVersion: string;
31
+ }): string;
32
+ export declare function createDownloadRetryMemory(options?: DownloadRetryMemoryOptions): DownloadRetryMemory;
33
+ //# sourceMappingURL=retry-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-memory.d.ts","sourceRoot":"","sources":["../../src/sync/retry-memory.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExE,MAAM,WAAW,0BAA0B;IACzC,sDAAsD;IACtD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,CAAC;IAC7C,6EAA6E;IAC7E,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IACrD,6DAA6D;IAC7D,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;;OAKG;IACH,cAAc,IAAI,IAAI,CAAC;CACxB;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,MAAM,CAET;AAQD,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,0BAA+B,GACvC,mBAAmB,CA4CrB"}
@@ -0,0 +1,68 @@
1
+ // Cross-cycle download retry memory.
2
+ //
3
+ // downloadAll re-lists the owner's data points every sync cycle (the cursor
4
+ // only advances past fully-successful pages, and a single-page listing has no
5
+ // nextCursor at all), so without memory a record whose blob fails to download
6
+ // is re-fetched on every cycle. With the DCR page triggering a sync per
7
+ // readiness poll, one missing blob produced a 700+ request 404 storm against
8
+ // storage (2026-07-08 prod incident).
9
+ //
10
+ // Policy:
11
+ // - non-retryable failures (deterministic — e.g. HTTP 404: the blob is not
12
+ // there and waiting cannot heal it): never attempt again for the lifetime
13
+ // of this memory (one attempt per boot session).
14
+ // - retryable failures (transient — 5xx, network): exponential backoff,
15
+ // capped at DEFAULT_MAX_TRANSIENT_ATTEMPTS attempts, then give up for the
16
+ // session.
17
+ //
18
+ // Keys pair the record id with its expectedVersion (`downloadRetryKey`), so a
19
+ // re-registered version — new bytes under a new blob key — always gets a
20
+ // fresh set of attempts.
21
+ export const DEFAULT_MAX_TRANSIENT_ATTEMPTS = 5;
22
+ export const DEFAULT_BACKOFF_BASE_MS = 30_000;
23
+ /** Retry-memory key for a data-point record: id + version. */
24
+ export function downloadRetryKey(record) {
25
+ return `${record.id}@${record.expectedVersion}`;
26
+ }
27
+ export function createDownloadRetryMemory(options = {}) {
28
+ const maxTransientAttempts = options.maxTransientAttempts ?? DEFAULT_MAX_TRANSIENT_ATTEMPTS;
29
+ const backoffBaseMs = options.backoffBaseMs ?? DEFAULT_BACKOFF_BASE_MS;
30
+ const now = options.now ?? Date.now;
31
+ // DPv2 keys one record per (owner, scope), so the map stays small — no
32
+ // eviction needed.
33
+ const entries = new Map();
34
+ return {
35
+ decide(key) {
36
+ const entry = entries.get(key);
37
+ if (!entry)
38
+ return "attempt";
39
+ if (entry.permanent || entry.attempts >= maxTransientAttempts) {
40
+ return "give-up";
41
+ }
42
+ return now() < entry.nextRetryAtMs ? "backoff" : "attempt";
43
+ },
44
+ recordFailure(key, retryable) {
45
+ if (!retryable) {
46
+ entries.set(key, { attempts: 0, nextRetryAtMs: 0, permanent: true });
47
+ return;
48
+ }
49
+ const attempts = (entries.get(key)?.attempts ?? 0) + 1;
50
+ entries.set(key, {
51
+ attempts,
52
+ nextRetryAtMs: now() + backoffBaseMs * 2 ** (attempts - 1),
53
+ permanent: false,
54
+ });
55
+ },
56
+ recordSuccess(key) {
57
+ entries.delete(key);
58
+ },
59
+ onListingReset() {
60
+ for (const [key, entry] of entries) {
61
+ if (!entry.permanent) {
62
+ entries.delete(key);
63
+ }
64
+ }
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=retry-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-memory.js","sourceRoot":"","sources":["../../src/sync/retry-memory.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,8EAA8E;AAC9E,wEAAwE;AACxE,6EAA6E;AAC7E,sCAAsC;AACtC,EAAE;AACF,UAAU;AACV,6EAA6E;AAC7E,8EAA8E;AAC9E,qDAAqD;AACrD,0EAA0E;AAC1E,8EAA8E;AAC9E,eAAe;AACf,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,yBAAyB;AAazB,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAkB9C,8DAA8D;AAC9D,MAAM,UAAU,gBAAgB,CAAC,MAGhC;IACC,OAAO,GAAG,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;AAClD,CAAC;AAQD,MAAM,UAAU,yBAAyB,CACvC,UAAsC,EAAE;IAExC,MAAM,oBAAoB,GACxB,OAAO,CAAC,oBAAoB,IAAI,8BAA8B,CAAC;IACjE,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAC;IACvE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,uEAAuE;IACvE,mBAAmB;IACnB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAE9C,OAAO;QACL,MAAM,CAAC,GAAG;YACR,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK;gBAAE,OAAO,SAAS,CAAC;YAC7B,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,QAAQ,IAAI,oBAAoB,EAAE,CAAC;gBAC9D,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7D,CAAC;QAED,aAAa,CAAC,GAAG,EAAE,SAAS;YAC1B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrE,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;gBACf,QAAQ;gBACR,aAAa,EAAE,GAAG,EAAE,GAAG,aAAa,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;gBAC1D,SAAS,EAAE,KAAK;aACjB,CAAC,CAAC;QACL,CAAC;QAED,aAAa,CAAC,GAAG;YACf,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,cAAc;YACZ,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;gBACnC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;oBACrB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}