@needmoretruth/nmts-cli 0.17.2 → 0.34.2

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 (419) hide show
  1. package/AGENTS.md +125 -517
  2. package/CHANGELOG.md +104 -0
  3. package/README.ko.md +377 -469
  4. package/README.md +394 -474
  5. package/dist/account-proof.d.ts +29 -0
  6. package/dist/account-proof.js +6 -6
  7. package/dist/account.d.ts +18 -0
  8. package/dist/account.js +5 -5
  9. package/dist/agent-host.d.ts +71 -0
  10. package/dist/agent-host.js +169 -0
  11. package/dist/api-advice.d.ts +2 -0
  12. package/dist/api-advice.js +210 -0
  13. package/dist/api-key.d.ts +79 -0
  14. package/dist/api-key.js +7 -7
  15. package/dist/api-refusal.d.ts +14 -0
  16. package/dist/api-refusal.js +8 -0
  17. package/dist/api.d.ts +114 -0
  18. package/dist/api.js +59 -162
  19. package/dist/args.d.ts +160 -0
  20. package/dist/args.js +118 -30
  21. package/dist/artifact-about.d.ts +49 -0
  22. package/dist/autonomy.d.ts +39 -0
  23. package/dist/autonomy.js +110 -32
  24. package/dist/code-access.d.ts +29 -0
  25. package/dist/code-access.js +3 -3
  26. package/dist/code-vault.d.ts +38 -0
  27. package/dist/code-vault.js +8 -8
  28. package/dist/collision.d.ts +67 -0
  29. package/dist/collision.js +1 -1
  30. package/dist/commands/accept-terms.d.ts +11 -0
  31. package/dist/commands/accept-terms.js +106 -0
  32. package/dist/commands/balance.d.ts +7 -0
  33. package/dist/commands/balance.js +54 -1
  34. package/dist/commands/create-code-file.d.ts +24 -0
  35. package/dist/commands/create-code-file.js +93 -0
  36. package/dist/commands/create-link.d.ts +10 -0
  37. package/dist/commands/create-link.js +232 -0
  38. package/dist/commands/create.d.ts +20 -0
  39. package/dist/commands/create.js +43 -102
  40. package/dist/commands/credits.d.ts +9 -0
  41. package/dist/commands/credits.js +110 -0
  42. package/dist/commands/delete-account.d.ts +11 -0
  43. package/dist/commands/delete-account.js +63 -0
  44. package/dist/commands/deposit.d.ts +7 -0
  45. package/dist/commands/deposit.js +85 -0
  46. package/dist/commands/devices.d.ts +12 -0
  47. package/dist/commands/devices.js +144 -0
  48. package/dist/commands/documents.d.ts +35 -0
  49. package/dist/commands/documents.js +212 -0
  50. package/dist/commands/env.d.ts +5 -0
  51. package/dist/commands/env.js +10 -2
  52. package/dist/commands/erase.d.ts +13 -0
  53. package/dist/commands/erase.js +193 -0
  54. package/dist/commands/expiring.d.ts +19 -0
  55. package/dist/commands/extend.d.ts +33 -0
  56. package/dist/commands/extend.js +54 -15
  57. package/dist/commands/get.d.ts +18 -0
  58. package/dist/commands/key-manage.d.ts +11 -0
  59. package/dist/commands/key-manage.js +162 -0
  60. package/dist/commands/key.d.ts +28 -0
  61. package/dist/commands/key.js +249 -0
  62. package/dist/commands/kit.d.ts +11 -0
  63. package/dist/commands/kit.js +7 -7
  64. package/dist/commands/listfile.d.ts +13 -0
  65. package/dist/commands/listfile.js +12 -5
  66. package/dist/commands/login.d.ts +18 -0
  67. package/dist/commands/login.js +19 -19
  68. package/dist/commands/logout.d.ts +1 -0
  69. package/dist/commands/logout.js +1 -1
  70. package/dist/commands/losses.d.ts +12 -0
  71. package/dist/commands/losses.js +180 -0
  72. package/dist/commands/ls.d.ts +23 -0
  73. package/dist/commands/marks-dispatch.d.ts +2 -0
  74. package/dist/commands/marks-dispatch.js +51 -0
  75. package/dist/commands/marks.d.ts +46 -0
  76. package/dist/commands/marks.js +80 -0
  77. package/dist/commands/mcp.d.ts +24 -0
  78. package/dist/commands/mcp.js +70 -5
  79. package/dist/commands/mode.d.ts +8 -0
  80. package/dist/commands/mode.js +60 -24
  81. package/dist/commands/on-collision.d.ts +6 -0
  82. package/dist/commands/organise.d.ts +46 -0
  83. package/dist/commands/padding.d.ts +7 -0
  84. package/dist/commands/padding.js +114 -0
  85. package/dist/commands/public-code.d.ts +9 -0
  86. package/dist/commands/public-code.js +8 -8
  87. package/dist/commands/pull.d.ts +27 -0
  88. package/dist/commands/push-wallet.d.ts +19 -0
  89. package/dist/commands/push-wallet.js +69 -0
  90. package/dist/commands/push.d.ts +47 -0
  91. package/dist/commands/push.js +37 -7
  92. package/dist/commands/put-wallet.d.ts +77 -0
  93. package/dist/commands/put-wallet.js +316 -0
  94. package/dist/commands/put.d.ts +56 -0
  95. package/dist/commands/put.js +53 -6
  96. package/dist/commands/rebuild.d.ts +18 -0
  97. package/dist/commands/rebuild.js +108 -10
  98. package/dist/commands/receive.d.ts +24 -0
  99. package/dist/commands/recovery-dispatch.d.ts +2 -0
  100. package/dist/commands/recovery-dispatch.js +34 -0
  101. package/dist/commands/recovery-list.d.ts +11 -0
  102. package/dist/commands/recovery-list.js +6 -6
  103. package/dist/commands/recovery.d.ts +25 -0
  104. package/dist/commands/recovery.js +2 -2
  105. package/dist/commands/rollback.d.ts +9 -0
  106. package/dist/commands/rollback.js +118 -0
  107. package/dist/commands/s3.d.ts +23 -0
  108. package/dist/commands/s3.js +6 -6
  109. package/dist/commands/settings.d.ts +5 -0
  110. package/dist/commands/settings.js +21 -6
  111. package/dist/commands/share-dispatch.d.ts +2 -0
  112. package/dist/commands/share-dispatch.js +46 -0
  113. package/dist/commands/share.d.ts +14 -0
  114. package/dist/commands/share.js +13 -3
  115. package/dist/commands/shares-sent.d.ts +18 -0
  116. package/dist/commands/shares-sent.js +95 -0
  117. package/dist/commands/support.d.ts +24 -0
  118. package/dist/commands/support.js +321 -0
  119. package/dist/commands/sweep.d.ts +11 -0
  120. package/dist/commands/tip.d.ts +11 -0
  121. package/dist/commands/tip.js +86 -0
  122. package/dist/commands/trash.d.ts +17 -0
  123. package/dist/commands/trash.js +1 -1
  124. package/dist/commands/trial.d.ts +7 -0
  125. package/dist/commands/trial.js +16 -18
  126. package/dist/commands/unlock.d.ts +16 -0
  127. package/dist/commands/unlock.js +159 -0
  128. package/dist/commands/update.d.ts +42 -0
  129. package/dist/commands/update.js +1 -1
  130. package/dist/commands/usage.d.ts +8 -0
  131. package/dist/commands/verify.d.ts +18 -0
  132. package/dist/commands/verify.js +10 -6
  133. package/dist/commands/wallet-activity.d.ts +26 -0
  134. package/dist/commands/wallet-activity.js +117 -0
  135. package/dist/commands/wallet-donate.d.ts +26 -0
  136. package/dist/commands/wallet-donate.js +163 -0
  137. package/dist/commands/wallet-hall.d.ts +35 -0
  138. package/dist/commands/wallet-hall.js +214 -0
  139. package/dist/commands/wallet-send.d.ts +22 -0
  140. package/dist/commands/wallet-send.js +153 -0
  141. package/dist/commands/wallet-storage-ops.d.ts +24 -0
  142. package/dist/commands/wallet-storage-ops.js +215 -0
  143. package/dist/commands/wallet-storage.d.ts +18 -0
  144. package/dist/commands/wallet-storage.js +95 -0
  145. package/dist/commands/wallet-swap.d.ts +32 -0
  146. package/dist/commands/wallet-swap.js +287 -0
  147. package/dist/commands/wallet.d.ts +36 -0
  148. package/dist/commands/wallet.js +57 -15
  149. package/dist/commands/whoami.d.ts +10 -0
  150. package/dist/commands/whoami.js +24 -6
  151. package/dist/consent.d.ts +140 -0
  152. package/dist/consent.js +89 -30
  153. package/dist/credentials.d.ts +146 -0
  154. package/dist/credentials.js +10 -10
  155. package/dist/crypto-surface.d.ts +197 -0
  156. package/dist/crypto.d.ts +81 -0
  157. package/dist/crypto.js +13 -0
  158. package/dist/deposit.d.ts +25 -0
  159. package/dist/deposit.js +78 -0
  160. package/dist/download-part.d.ts +40 -0
  161. package/dist/download-sink.d.ts +76 -0
  162. package/dist/download.d.ts +79 -0
  163. package/dist/download.js +3 -3
  164. package/dist/drive-paths.d.ts +73 -0
  165. package/dist/environment.d.ts +62 -0
  166. package/dist/environment.js +29 -9
  167. package/dist/errors.d.ts +22 -0
  168. package/dist/errors.js +3 -3
  169. package/dist/exit.d.ts +44 -0
  170. package/dist/expiry.d.ts +58 -0
  171. package/dist/extend-budget.d.ts +35 -0
  172. package/dist/extend-budget.js +81 -0
  173. package/dist/extend-chain.d.ts +43 -0
  174. package/dist/extend-chain.js +40 -3
  175. package/dist/extend-plan.d.ts +148 -0
  176. package/dist/extend-plan.js +1 -1
  177. package/dist/gate.d.ts +18 -0
  178. package/dist/gate.js +100 -0
  179. package/dist/guards.d.ts +2 -0
  180. package/dist/help.d.ts +20 -0
  181. package/dist/help.js +199 -33
  182. package/dist/human-check.d.ts +23 -0
  183. package/dist/index.d.ts +42 -0
  184. package/dist/index.js +49 -0
  185. package/dist/item-trash.d.ts +1 -0
  186. package/dist/kit-file.d.ts +56 -0
  187. package/dist/kit-file.js +10 -10
  188. package/dist/list-file.d.ts +88 -0
  189. package/dist/list-file.js +90 -7
  190. package/dist/list-view-find.d.ts +15 -0
  191. package/dist/list-view-order.d.ts +32 -0
  192. package/dist/main.d.ts +12 -0
  193. package/dist/main.js +112 -113
  194. package/dist/manifest-chunk-cache.d.ts +14 -0
  195. package/dist/manifest-chunk-cache.js +103 -0
  196. package/dist/manifest-chunk-flow.d.ts +81 -0
  197. package/dist/manifest-chunk-flow.js +307 -0
  198. package/dist/manifest-create.d.ts +23 -0
  199. package/dist/manifest-create.js +26 -30
  200. package/dist/manifest-write.d.ts +161 -0
  201. package/dist/manifest-write.js +42 -33
  202. package/dist/manifest.d.ts +82 -0
  203. package/dist/manifest.js +69 -21
  204. package/dist/mark-render.d.ts +26 -0
  205. package/dist/mcp-args.d.ts +17 -0
  206. package/dist/mcp-ask.d.ts +43 -0
  207. package/dist/mcp-ask.js +100 -0
  208. package/dist/mcp-tools/context.d.ts +46 -0
  209. package/dist/mcp-tools/credits.d.ts +3 -0
  210. package/dist/mcp-tools/credits.js +61 -0
  211. package/dist/mcp-tools/files.d.ts +3 -0
  212. package/dist/mcp-tools/files.js +34 -0
  213. package/dist/mcp-tools/organise.d.ts +3 -0
  214. package/dist/mcp-tools/organise.js +82 -2
  215. package/dist/mcp-tools/reads.d.ts +3 -0
  216. package/dist/mcp-tools/reads.js +132 -4
  217. package/dist/mcp-tools/share.d.ts +3 -0
  218. package/dist/mcp-tools/share.js +26 -7
  219. package/dist/mcp-tools/support.d.ts +3 -0
  220. package/dist/mcp-tools/support.js +140 -0
  221. package/dist/mcp-tools/tiers.d.ts +31 -0
  222. package/dist/mcp-tools/tiers.js +147 -0
  223. package/dist/mcp.d.ts +80 -0
  224. package/dist/mcp.js +110 -9
  225. package/dist/net-retry.d.ts +38 -0
  226. package/dist/network.d.ts +10 -0
  227. package/dist/notice.d.ts +7 -0
  228. package/dist/notice.js +7 -7
  229. package/dist/product.d.ts +29 -0
  230. package/dist/product.js +1 -1
  231. package/dist/progress.d.ts +37 -0
  232. package/dist/prompt.d.ts +31 -0
  233. package/dist/prompt.js +1 -1
  234. package/dist/rebuild-key-check.d.ts +26 -0
  235. package/dist/rebuild-key-check.js +90 -0
  236. package/dist/rebuild.d.ts +87 -0
  237. package/dist/rebuild.js +26 -4
  238. package/dist/recovery-assemble.d.ts +40 -0
  239. package/dist/recovery-assemble.js +1 -1
  240. package/dist/recovery-build.d.ts +40 -0
  241. package/dist/recovery-map-file.d.ts +53 -0
  242. package/dist/recovery-map-file.js +4 -4
  243. package/dist/recovery-map.d.ts +197 -0
  244. package/dist/recovery-release.d.ts +104 -0
  245. package/dist/recovery-seq.d.ts +10 -0
  246. package/dist/recovery-source.d.ts +50 -0
  247. package/dist/redact.d.ts +70 -0
  248. package/dist/redact.js +212 -0
  249. package/dist/registration.d.ts +30 -0
  250. package/dist/registration.js +5 -5
  251. package/dist/risk.d.ts +380 -0
  252. package/dist/risk.js +206 -0
  253. package/dist/run-log.d.ts +78 -0
  254. package/dist/run-log.js +301 -0
  255. package/dist/s3/listing.d.ts +47 -0
  256. package/dist/s3/multipart.d.ts +21 -0
  257. package/dist/s3/response-sink.d.ts +8 -0
  258. package/dist/s3/same-file.d.ts +54 -0
  259. package/dist/s3/server.d.ts +58 -0
  260. package/dist/s3/server.js +2 -2
  261. package/dist/s3/sigv4.d.ts +46 -0
  262. package/dist/s3/sigv4.js +1 -1
  263. package/dist/s3/staging.d.ts +10 -0
  264. package/dist/s3/xml.d.ts +28 -0
  265. package/dist/safe-path.d.ts +41 -0
  266. package/dist/seal.d.ts +120 -0
  267. package/dist/secret-reader.d.ts +28 -0
  268. package/dist/server.d.ts +9 -0
  269. package/dist/session.d.ts +32 -0
  270. package/dist/session.js +1 -1
  271. package/dist/setup-questions.d.ts +7 -0
  272. package/dist/share.d.ts +108 -0
  273. package/dist/share.js +1 -1
  274. package/dist/shared/lib/crypto/size-padding.d.ts +55 -0
  275. package/dist/shared/lib/crypto/size-padding.js +5 -0
  276. package/dist/shared/lib/drive/manifest-chunks.d.ts +95 -0
  277. package/dist/shared/lib/drive/manifest-chunks.js +252 -0
  278. package/dist/shared/lib/drive/manifest-codec.d.ts +214 -0
  279. package/dist/shared/lib/drive/manifest-codec.js +7 -7
  280. package/dist/shared/lib/drive/manifest-index.d.ts +98 -0
  281. package/dist/shared/lib/drive/manifest-ops.d.ts +167 -0
  282. package/dist/shared/lib/drive/manifest-ops.js +9 -4
  283. package/dist/shared/lib/drive/manifest-pack.d.ts +65 -0
  284. package/dist/shared/lib/drive/manifest-pack.js +287 -0
  285. package/dist/shared/lib/drive/manifest-settings.d.ts +113 -0
  286. package/dist/shared/lib/drive/manifest-settings.js +87 -6
  287. package/dist/shared/lib/drive/name-conflict.d.ts +76 -0
  288. package/dist/shared/lib/drive/rebuild-verify.d.ts +73 -0
  289. package/dist/shared/lib/drive/rebuild-verify.js +112 -0
  290. package/dist/shared/lib/drive/unique-name.d.ts +9 -0
  291. package/dist/shared/lib/drive/zstd.d.ts +27 -0
  292. package/dist/shared/lib/drive/zstd.js +74 -0
  293. package/dist/shared/lib/extend/epochs.d.ts +205 -0
  294. package/dist/shared/lib/net/retry-budget.d.ts +79 -0
  295. package/dist/shared/lib/share/shared-file-info.d.ts +21 -0
  296. package/dist/shared/lib/storage-control/chain.d.ts +57 -0
  297. package/dist/shared/lib/storage-control/chain.js +82 -0
  298. package/dist/shared/lib/storage-control/plan.d.ts +40 -0
  299. package/dist/shared/lib/storage-control/plan.js +72 -0
  300. package/dist/shared/lib/storage-control/reuse.d.ts +72 -0
  301. package/dist/shared/lib/storage-control/reuse.js +95 -0
  302. package/dist/shared/lib/storage-network.d.ts +25 -0
  303. package/dist/shared/lib/upload/part-plan.d.ts +24 -0
  304. package/dist/shared/lib/wallet/activity.d.ts +138 -0
  305. package/dist/shared/lib/wallet/activity.js +208 -0
  306. package/dist/shared/lib/wallet/send-rules.d.ts +68 -0
  307. package/dist/shared/lib/wallet/send-rules.js +116 -0
  308. package/dist/shared/lib/wallet/swap-rules.d.ts +115 -0
  309. package/dist/shared/lib/wallet/swap-rules.js +199 -0
  310. package/dist/shared/lib/wallet/tip.d.ts +14 -0
  311. package/dist/shared/lib/wallet/tip.js +34 -0
  312. package/dist/shared/lib/wallet/venue-ids.d.ts +23 -0
  313. package/dist/shared/lib/wallet/venue-ids.js +53 -0
  314. package/dist/standing-tip.d.ts +24 -0
  315. package/dist/standing-tip.js +52 -0
  316. package/dist/stdout.d.ts +38 -0
  317. package/dist/storage-control-chain.d.ts +38 -0
  318. package/dist/storage-control-chain.js +78 -0
  319. package/dist/sui-rpc.d.ts +15 -0
  320. package/dist/sui-rpc.js +59 -0
  321. package/dist/support-attach.d.ts +24 -0
  322. package/dist/support-attach.js +72 -0
  323. package/dist/support-copy.d.ts +42 -0
  324. package/dist/support-copy.js +109 -0
  325. package/dist/support-wire.d.ts +49 -0
  326. package/dist/support-wire.js +194 -0
  327. package/dist/trash-sweep.d.ts +55 -0
  328. package/dist/units.d.ts +2 -0
  329. package/dist/update-check.d.ts +50 -0
  330. package/dist/update-source.d.ts +63 -0
  331. package/dist/upload-api.d.ts +3 -0
  332. package/dist/upload-file.d.ts +97 -0
  333. package/dist/upload-file.js +3 -2
  334. package/dist/upload-price.d.ts +50 -0
  335. package/dist/upload-steps.d.ts +26 -0
  336. package/dist/upload-steps.js +29 -9
  337. package/dist/upload-store.d.ts +182 -0
  338. package/dist/upload-wallet-chain.d.ts +54 -0
  339. package/dist/upload-wallet-chain.js +203 -0
  340. package/dist/upload-wallet-plan.d.ts +128 -0
  341. package/dist/upload-wallet-plan.js +184 -0
  342. package/dist/upload-wallet.d.ts +24 -0
  343. package/dist/upload-wallet.js +208 -0
  344. package/dist/upload-wire.d.ts +244 -0
  345. package/dist/upload.d.ts +18 -0
  346. package/dist/upload.js +10 -0
  347. package/dist/usage-report.d.ts +35 -0
  348. package/dist/wallet-activity-chain.d.ts +5 -0
  349. package/dist/wallet-activity-chain.js +31 -0
  350. package/dist/wallet-chain.d.ts +19 -0
  351. package/dist/wallet-chain.js +2 -2
  352. package/dist/wallet-grant.d.ts +50 -0
  353. package/dist/wallet-grant.js +218 -0
  354. package/dist/wallet-send-chain.d.ts +24 -0
  355. package/dist/wallet-send-chain.js +49 -0
  356. package/dist/wallet-sign.d.ts +133 -0
  357. package/dist/wallet-sign.js +317 -0
  358. package/dist/wallet-storage-chain.d.ts +3 -0
  359. package/dist/wallet-storage-chain.js +20 -0
  360. package/dist/wallet-swap-chain.d.ts +52 -0
  361. package/dist/wallet-swap-chain.js +186 -0
  362. package/dist/wallet-swap-quote.d.ts +22 -0
  363. package/dist/wallet-swap-quote.js +126 -0
  364. package/dist/wallet.d.ts +135 -0
  365. package/dist/wallet.js +5 -5
  366. package/dist/walrus-write.d.ts +56 -0
  367. package/dist/walrus-write.js +5 -4
  368. package/dist/walrus.d.ts +86 -0
  369. package/dist/walrus.js +48 -10
  370. package/dist/zstd-node.d.ts +11 -0
  371. package/dist/zstd-node.js +71 -0
  372. package/docs/commands/accept-terms.md +15 -0
  373. package/docs/commands/create.md +17 -0
  374. package/docs/commands/credits.md +34 -0
  375. package/docs/commands/delete-account.md +14 -0
  376. package/docs/commands/deposit.md +27 -0
  377. package/docs/commands/devices.md +9 -0
  378. package/docs/commands/documents.md +10 -0
  379. package/docs/commands/env.md +21 -0
  380. package/docs/commands/extend.md +27 -0
  381. package/docs/commands/folders.md +10 -0
  382. package/docs/commands/get.md +14 -0
  383. package/docs/commands/key.md +14 -0
  384. package/docs/commands/login.md +23 -0
  385. package/docs/commands/logout.md +11 -0
  386. package/docs/commands/losses.md +13 -0
  387. package/docs/commands/ls.md +16 -0
  388. package/docs/commands/marks.md +9 -0
  389. package/docs/commands/mcp.md +33 -0
  390. package/docs/commands/mode.md +29 -0
  391. package/docs/commands/on-collision.md +13 -0
  392. package/docs/commands/padding.md +13 -0
  393. package/docs/commands/public-code.md +9 -0
  394. package/docs/commands/pull.md +9 -0
  395. package/docs/commands/push.md +12 -0
  396. package/docs/commands/put.md +36 -0
  397. package/docs/commands/rebuild.md +13 -0
  398. package/docs/commands/recovery.md +18 -0
  399. package/docs/commands/s3.md +17 -0
  400. package/docs/commands/share.md +15 -0
  401. package/docs/commands/support.md +16 -0
  402. package/docs/commands/tip.md +21 -0
  403. package/docs/commands/trash.md +25 -0
  404. package/docs/commands/trial.md +12 -0
  405. package/docs/commands/unlock.md +25 -0
  406. package/docs/commands/update.md +14 -0
  407. package/docs/commands/usage.md +14 -0
  408. package/docs/commands/verify.md +18 -0
  409. package/docs/commands/wallet.md +67 -0
  410. package/docs/commands/whoami.md +12 -0
  411. package/package.json +67 -8
  412. package/server.json +28 -0
  413. package/vendor/nmts-crypto/nmts_crypto_wasm.d.ts +23 -2
  414. package/vendor/nmts-crypto/nmts_crypto_wasm.js +44 -2
  415. package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm +0 -0
  416. package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm.d.ts +1 -0
  417. package/vendor/nmts-crypto/package.json +1 -1
  418. package/dist/commands/consent.js +0 -77
  419. package/dist/extend-sign.js +0 -130
@@ -0,0 +1,167 @@
1
+ import type { AccountSettings, ManifestEntry } from "./manifest-codec.ts";
2
+ /** One drive edit, in a form that can be replayed onto a newer list. */
3
+ export type ManifestIntent =
4
+ /** Insert or replace by id. Upload-commit and folder-create both land here. */
5
+ {
6
+ op: "add";
7
+ entry: ManifestEntry;
8
+ }
9
+ /** New plaintext name for one item. */
10
+ | {
11
+ op: "rename";
12
+ id: string;
13
+ name: string;
14
+ at: number;
15
+ }
16
+ /** New parent (null = drive root). */
17
+ | {
18
+ op: "move";
19
+ id: string;
20
+ parentId: string | null;
21
+ at: number;
22
+ }
23
+ /** Send to the trash. Already-trashed ids keep their original instant. */
24
+ | {
25
+ op: "trash";
26
+ ids: readonly string[];
27
+ at: number;
28
+ }
29
+ /** Bring back out of the trash. */
30
+ | {
31
+ op: "restore";
32
+ ids: readonly string[];
33
+ at: number;
34
+ }
35
+ /** Remove from the list entirely — the storage record is gone or going. */
36
+ | {
37
+ op: "purge";
38
+ ids: readonly string[];
39
+ }
40
+ /** Star / unstar. `on` is the DESIRED state, never a toggle: a replayed toggle would flip twice. */
41
+ | {
42
+ op: "favorite";
43
+ ids: readonly string[];
44
+ on: boolean;
45
+ at: number;
46
+ }
47
+ /** Pin / unpin to the top of the item's own folder. Same desired-state rule as favourite. */
48
+ | {
49
+ op: "pin";
50
+ ids: readonly string[];
51
+ on: boolean;
52
+ at: number;
53
+ }
54
+ /** Put one label on (or take it off) these items. */
55
+ | {
56
+ op: "label";
57
+ ids: readonly string[];
58
+ label: string;
59
+ on: boolean;
60
+ at: number;
61
+ }
62
+ /** Rename a label everywhere it appears. Items already wearing `to` do not gain a duplicate. */
63
+ | {
64
+ op: "labelRename";
65
+ from: string;
66
+ to: string;
67
+ at: number;
68
+ }
69
+ /** Remove a label from every item — which is what makes it stop existing. */
70
+ | {
71
+ op: "labelDelete";
72
+ label: string;
73
+ at: number;
74
+ }
75
+ /**
76
+ * Write MY OWN receipt that this file was shared with this address.
77
+ *
78
+ * Upsert by address, because the server replaces rather than stacks a re-share to the same
79
+ * person (`shares_one_per_recipient`); a second receipt would show one recipient twice.
80
+ */
81
+ | {
82
+ op: "shareRecord";
83
+ id: string;
84
+ address: string;
85
+ at: number;
86
+ }
87
+ /** Mark a receipt as revoked — a revocation was sent. No-op when there is no receipt for that address. */
88
+ | {
89
+ op: "shareRevoked";
90
+ id: string;
91
+ address: string;
92
+ at: number;
93
+ }
94
+ /**
95
+ * Drop receipts the server's listing has confirmed gone.
96
+ *
97
+ * ⛔ ONLY REVOKED RECEIPTS ARE DROPPED. An active receipt whose row is missing is the entire
98
+ * point of keeping receipts — pruning it would erase the warning instead of showing it — and
99
+ * the restriction is also what makes this intent safe to replay onto a list where the address
100
+ * was just re-shared.
101
+ */
102
+ | {
103
+ op: "sharePrune";
104
+ id: string;
105
+ addresses: readonly string[];
106
+ at: number;
107
+ };
108
+ /**
109
+ * Apply one intent, returning a new list. The input is never mutated: the store keeps the
110
+ * pre-save snapshot around to rebuild from after a version conflict.
111
+ *
112
+ * Returns the SAME array reference when nothing changed, so callers can skip a re-render and a
113
+ * save for an intent that turned out to be a no-op (a rename to the name it already had, a trash
114
+ * of something another device already purged).
115
+ */
116
+ export declare function applyIntent(entries: readonly ManifestEntry[], intent: ManifestIntent): readonly ManifestEntry[];
117
+ /**
118
+ * Which size-padding rule an account seals its next upload under.
119
+ *
120
+ * ⛔ DECLARED BESIDE THE PATCH THAT CARRIES IT, not in `lib/crypto/padding.ts` where the padding
121
+ * itself lives. `padding.ts` imports it from here. The direction matters: this file is copied
122
+ * byte-for-byte into the `nmts` command-line package, and a type reaching out of it into the
123
+ * crypto tree would drag that whole tree along with it for the sake of two string literals.
124
+ */
125
+ export type PaddingMode = "padme" | "pow2" | "none";
126
+ /**
127
+ * One account-settings edit, as DESIRED STATE per field — never "toggle", so replaying it onto a
128
+ * list another device wrote lands the same answer. A default value means absence in the codec.
129
+ */
130
+ export interface SettingsPatch {
131
+ developerMode?: boolean;
132
+ textScalePct?: number;
133
+ /** Which rule seals future uploads: `"padme"` = the default, `"none"` = the file's exact length. */
134
+ paddingMode?: PaddingMode;
135
+ /** Credits held back with each credit-paid upload, 0 to `DEPOSIT_MAX_CREDITS`. */
136
+ depositDefault?: number;
137
+ /** The standing tip in tenths of a percent (0 = none) and the instant its terms were agreed to (0 clears). */
138
+ tipTenths?: number;
139
+ tipConsentAt?: number;
140
+ }
141
+ /**
142
+ * Apply one settings patch, returning new settings. Returns the SAME reference when nothing
143
+ * changed, so callers can skip a save (a version bump every other device must download).
144
+ *
145
+ * A text scale is CLAMPED into the codec's bounds here — this is the one write path, so a value
146
+ * the slider or the typed field lets through never reaches the wire out of range.
147
+ */
148
+ export declare function applySettingsPatch(settings: AccountSettings, patch: SettingsPatch): AccountSettings;
149
+ /** Replay a whole queue in order. Used to rebuild after a version conflict. */
150
+ export declare function applyIntents(entries: readonly ManifestEntry[], intents: readonly ManifestIntent[]): readonly ManifestEntry[];
151
+ /**
152
+ * True when the intent touches storage the server also tracks, so a save must not be deferred.
153
+ *
154
+ * A queued save that dies with the tab is recoverable for a rename (the name is only in the
155
+ * manifest, and losing it leaves the old name — annoying, not damaging). It is NOT recoverable
156
+ * when a file was just committed or just deleted: the storage record moved, and a manifest that
157
+ * disagrees leaves a file that is paid for but invisible, or one that shows but is gone.
158
+ *
159
+ * Stars, pins and labels are deliberately NOT in this list: they exist only in the manifest, so the
160
+ * worst a lost save can do is leave a file unstarred — the same recoverable loss as a rename.
161
+ *
162
+ * SHARE RECEIPTS ARE, for the same reason a commit is: they describe a row the server now
163
+ * holds, and nothing else on this side records it. A receipt lost with the tab does not degrade to
164
+ * a wrong colour — it degrades to a share this device can never again hold the server to.
165
+ * `sharePrune` stays out: losing it leaves a settled receipt that the next listing prunes again.
166
+ */
167
+ export declare function mustSaveNow(intent: ManifestIntent): boolean;
@@ -1,5 +1,6 @@
1
1
  // Runtime import (relative + .ts — the header's node --test rule) for the bounds the patch obeys.
2
2
  import { TEXT_SCALE_DEFAULT_PCT, TEXT_SCALE_MAX_PCT, TEXT_SCALE_MIN_PCT, } from "./manifest-codec.js";
3
+ import { applyDepositPatch, applyTipPatch } from "./manifest-settings.js";
3
4
  /**
4
5
  * Apply one intent, returning a new list. The input is never mutated: the store keeps the
5
6
  * pre-save snapshot around to rebuild from after a version conflict.
@@ -176,8 +177,8 @@ export function applySettingsPatch(settings, patch) {
176
177
  if (patch.paddingMode !== undefined) {
177
178
  // The default is spelled as absence, like every other field here — so two devices that both
178
179
  // "choose the default" write the same bytes and neither bumps the list's version.
179
- if (patch.paddingMode === "pow2")
180
- next.paddingMode = "pow2";
180
+ if (patch.paddingMode === "pow2" || patch.paddingMode === "none")
181
+ next.paddingMode = patch.paddingMode;
181
182
  else
182
183
  delete next.paddingMode;
183
184
  }
@@ -188,9 +189,13 @@ export function applySettingsPatch(settings, patch) {
188
189
  else
189
190
  next.textScalePct = pct;
190
191
  }
192
+ applyDepositPatch(next, patch.depositDefault);
193
+ applyTipPatch(next, patch.tipTenths, patch.tipConsentAt);
191
194
  const same = (next.developerMode === true) === (settings.developerMode === true) &&
192
- next.paddingMode === settings.paddingMode &&
193
- next.textScalePct === settings.textScalePct;
195
+ next.paddingMode === settings.paddingMode && next.depositDefault === settings.depositDefault &&
196
+ next.textScalePct === settings.textScalePct &&
197
+ next.tipTenths === settings.tipTenths &&
198
+ next.tipConsentAt === settings.tipConsentAt;
194
199
  return same ? settings : next;
195
200
  }
196
201
  /** Replay a whole queue in order. Used to rebuild after a version conflict. */
@@ -0,0 +1,65 @@
1
+ import { type ManifestEntry } from "./manifest-codec.ts";
2
+ import { type ManifestIndex } from "./manifest-index.ts";
3
+ /**
4
+ * The marker an entry gets when its parent chain does not reach the drive root.
5
+ *
6
+ * U+FFFF is a permanent noncharacter, so no name can contain it and it sorts after every assigned
7
+ * character in both code-point and UTF-16 order. That is what puts "placed after every entry that
8
+ * can be resolved" (§6.3.3) INSIDE the key, where any comparator honours it.
9
+ */
10
+ export declare const UNRESOLVED_MARK = "\uFFFF";
11
+ /**
12
+ * One chunk as the packer decided it.
13
+ *
14
+ * `reuse` is a chunk's existing name: present when its entry set came through an edit untouched,
15
+ * so the flow can name it in the new index without writing a byte. Absent means "seal these
16
+ * entries and write them".
17
+ */
18
+ export interface PackedChunk {
19
+ reuse?: string;
20
+ items: readonly ManifestEntry[];
21
+ /** Placement key of the first entry. */
22
+ f: string;
23
+ /** Placement key of the last entry. */
24
+ l: string;
25
+ }
26
+ /** A chunk this device currently holds open, as the flow read it out of the index. */
27
+ export interface HeldChunk {
28
+ /** Its name — the hash the index gave it. */
29
+ h: string;
30
+ f: string;
31
+ l: string;
32
+ items: readonly ManifestEntry[];
33
+ }
34
+ /**
35
+ * The placement key of one entry: its folder path from the drive root, each segment the folder's
36
+ * plaintext name, then the entry's own name, joined by `/`.
37
+ *
38
+ * Trashed entries keep the key they had — the trash is a mark on an entry, not a place — so
39
+ * nothing here reads `deletedAt`.
40
+ */
41
+ export declare function placementKey(entry: ManifestEntry, index: ManifestIndex): string;
42
+ /**
43
+ * Compare two placement keys BY CODE POINT, as §6.3.3 requires.
44
+ *
45
+ * JavaScript's own `<` compares UTF-16 code units, which puts an astral character (U+10000 and up,
46
+ * stored as a surrogate pair starting at U+D800) BEFORE U+E000–U+FFFF instead of after it. That is
47
+ * a different order from the one the format specifies, so keys carrying a surrogate take the exact
48
+ * path; everything else takes the fast one, which is the same order for those strings.
49
+ */
50
+ export declare function comparePlacementKeys(a: string, b: string): number;
51
+ /**
52
+ * Pack every entry from scratch, in key order, closing a chunk when the next entry would push its
53
+ * plaintext past the bound. Used for the first save of an account and for the version-1
54
+ * conversion (§6.3.6).
55
+ */
56
+ export declare function packAll(entries: readonly ManifestEntry[]): PackedChunk[];
57
+ /**
58
+ * The minimal rewrite: keep every chunk whose entries came through the edit untouched, rewrite the
59
+ * ones that changed, split what grew past the bound and merge what shrank under half of it.
60
+ *
61
+ * An entry stays in the chunk that held it only while its key is still inside that chunk's range.
62
+ * A move between folders changes the key, so it leaves as a removal and arrives as an addition —
63
+ * which is exactly the "at most two chunks" §6.3.3 describes.
64
+ */
65
+ export declare function repack(previous: readonly HeldChunk[], entries: readonly ManifestEntry[]): PackedChunk[];
@@ -0,0 +1,287 @@
1
+ // Placement and packing for the chunked file list — NCF-3 §6.3.3. ⚠ PUBLISHED — copied
2
+ // byte-for-byte into the `nmts` command-line package; keep comments self-contained English.
3
+ //
4
+ // WHAT THIS DECIDES: which entry goes in which chunk, and — for a save — which chunks can be kept
5
+ // by name because nothing inside them moved. That second answer is the whole point of format
6
+ // version 2: an edit that touches one file must upload one chunk, not the list.
7
+ //
8
+ // PURE: no I/O, no crypto, no React. It takes entries and the previous chunks and returns a plan;
9
+ // sealing, naming and writing are `manifest-chunk-flow.ts`'s job.
10
+ //
11
+ // PLACEMENT IS THE WRITER'S DUTY AND THE READER'S CONVENIENCE. A reader must find an entry by
12
+ // opening every chunk the index names; it MAY open the one whose range covers the folder on
13
+ // screen first. So a writer that gets placement wrong has written a slow list, not a wrong one —
14
+ // which is why the fallbacks below prefer "repack everything" over "refuse".
15
+ import { toWire } from "./manifest-codec.js";
16
+ import { buildIndex, pathOf } from "./manifest-index.js";
17
+ import { CHUNK_PLAIN_MAX } from "./manifest-chunks.js";
18
+ /**
19
+ * The marker an entry gets when its parent chain does not reach the drive root.
20
+ *
21
+ * U+FFFF is a permanent noncharacter, so no name can contain it and it sorts after every assigned
22
+ * character in both code-point and UTF-16 order. That is what puts "placed after every entry that
23
+ * can be resolved" (§6.3.3) INSIDE the key, where any comparator honours it.
24
+ */
25
+ export const UNRESOLVED_MARK = "\uFFFF";
26
+ /** Bytes for `{"v":2,"seq":<up to 16 digits>,"items":[]}` — the wrapper around a chunk's items. */
27
+ const CHUNK_DOC_OVERHEAD = 41;
28
+ const utf8 = new TextEncoder();
29
+ /** A key holding one half of a surrogate pair needs the slow, exact comparator below. */
30
+ const HAS_SURROGATE = /[\uD800-\uDFFF]/;
31
+ /**
32
+ * The placement key of one entry: its folder path from the drive root, each segment the folder's
33
+ * plaintext name, then the entry's own name, joined by `/`.
34
+ *
35
+ * Trashed entries keep the key they had — the trash is a mark on an entry, not a place — so
36
+ * nothing here reads `deletedAt`.
37
+ */
38
+ export function placementKey(entry, index) {
39
+ const key = [...pathOf(index, entry), entry.name].join("/");
40
+ return reachesRoot(index, entry) ? key : UNRESOLVED_MARK + key;
41
+ }
42
+ /** Whether this entry's parent chain ends at the root rather than at a gap or a loop. */
43
+ function reachesRoot(index, entry) {
44
+ const seen = new Set([entry.id]);
45
+ let parentId = entry.parentId;
46
+ while (parentId !== null) {
47
+ if (seen.has(parentId))
48
+ return false;
49
+ seen.add(parentId);
50
+ const parent = index.byId.get(parentId);
51
+ if (!parent)
52
+ return false;
53
+ parentId = parent.parentId;
54
+ }
55
+ return true;
56
+ }
57
+ /**
58
+ * Compare two placement keys BY CODE POINT, as §6.3.3 requires.
59
+ *
60
+ * JavaScript's own `<` compares UTF-16 code units, which puts an astral character (U+10000 and up,
61
+ * stored as a surrogate pair starting at U+D800) BEFORE U+E000–U+FFFF instead of after it. That is
62
+ * a different order from the one the format specifies, so keys carrying a surrogate take the exact
63
+ * path; everything else takes the fast one, which is the same order for those strings.
64
+ */
65
+ export function comparePlacementKeys(a, b) {
66
+ if (a === b)
67
+ return 0;
68
+ if (!HAS_SURROGATE.test(a) && !HAS_SURROGATE.test(b))
69
+ return a < b ? -1 : 1;
70
+ const ca = Array.from(a);
71
+ const cb = Array.from(b);
72
+ const n = Math.min(ca.length, cb.length);
73
+ for (let i = 0; i < n; i += 1) {
74
+ const pa = ca[i]?.codePointAt(0) ?? 0;
75
+ const pb = cb[i]?.codePointAt(0) ?? 0;
76
+ if (pa !== pb)
77
+ return pa < pb ? -1 : 1;
78
+ }
79
+ return ca.length - cb.length;
80
+ }
81
+ function keyAll(entries) {
82
+ const index = buildIndex(entries);
83
+ const keyed = entries.map((entry) => {
84
+ const json = JSON.stringify(toWire(entry));
85
+ const key = placementKey(entry, index);
86
+ return { entry, key, json, bytes: utf8.encode(json).length, astral: HAS_SURROGATE.test(key) };
87
+ });
88
+ keyed.sort(order);
89
+ return keyed;
90
+ }
91
+ /** Placement order, with the entry id as the tie-break so two same-named files never swap places. */
92
+ function order(a, b) {
93
+ const byKey = a.astral || b.astral
94
+ ? comparePlacementKeys(a.key, b.key)
95
+ : a.key < b.key
96
+ ? -1
97
+ : a.key > b.key
98
+ ? 1
99
+ : 0;
100
+ return byKey !== 0 ? byKey : a.entry.id < b.entry.id ? -1 : a.entry.id > b.entry.id ? 1 : 0;
101
+ }
102
+ /** The plaintext a chunk holding exactly these entries would occupy. */
103
+ function sizeOf(items) {
104
+ let total = CHUNK_DOC_OVERHEAD;
105
+ for (const k of items)
106
+ total += k.bytes + 1;
107
+ return items.length === 0 ? CHUNK_DOC_OVERHEAD : total - 1;
108
+ }
109
+ /**
110
+ * Pack every entry from scratch, in key order, closing a chunk when the next entry would push its
111
+ * plaintext past the bound. Used for the first save of an account and for the version-1
112
+ * conversion (§6.3.6).
113
+ */
114
+ export function packAll(entries) {
115
+ return close(fill(keyAll(entries)));
116
+ }
117
+ /** Greedy fill in key order — the "unused remainder is left unused" rule of §6.3.3. */
118
+ function fill(keyed) {
119
+ const out = [];
120
+ let current = [];
121
+ let size = CHUNK_DOC_OVERHEAD;
122
+ for (const k of keyed) {
123
+ const next = size + k.bytes + (current.length === 0 ? 0 : 1);
124
+ if (current.length > 0 && next > CHUNK_PLAIN_MAX) {
125
+ out.push(current);
126
+ current = [k];
127
+ size = CHUNK_DOC_OVERHEAD + k.bytes;
128
+ continue;
129
+ }
130
+ current.push(k);
131
+ size = next;
132
+ }
133
+ if (current.length > 0)
134
+ out.push(current);
135
+ return out;
136
+ }
137
+ /** Turn buckets into the plan the flow writes, dropping any that ended up empty. */
138
+ function close(buckets, reuse = []) {
139
+ const out = [];
140
+ for (let i = 0; i < buckets.length; i += 1) {
141
+ const items = buckets[i] ?? [];
142
+ if (items.length === 0)
143
+ continue;
144
+ const name = reuse[i];
145
+ out.push({
146
+ ...(name ? { reuse: name } : {}),
147
+ items: items.map((k) => k.entry),
148
+ f: items[0]?.key ?? "",
149
+ l: items[items.length - 1]?.key ?? "",
150
+ });
151
+ }
152
+ return out;
153
+ }
154
+ /**
155
+ * The minimal rewrite: keep every chunk whose entries came through the edit untouched, rewrite the
156
+ * ones that changed, split what grew past the bound and merge what shrank under half of it.
157
+ *
158
+ * An entry stays in the chunk that held it only while its key is still inside that chunk's range.
159
+ * A move between folders changes the key, so it leaves as a removal and arrives as an addition —
160
+ * which is exactly the "at most two chunks" §6.3.3 describes.
161
+ */
162
+ export function repack(previous, entries) {
163
+ if (previous.length === 0)
164
+ return packAll(entries);
165
+ const keyed = keyAll(entries);
166
+ const owner = new Map();
167
+ for (let i = 0; i < previous.length; i += 1) {
168
+ for (const e of previous[i]?.items ?? [])
169
+ owner.set(e.id, i);
170
+ }
171
+ const buckets = previous.map(() => []);
172
+ for (const k of keyed) {
173
+ const held = owner.get(k.entry.id);
174
+ const home = held !== undefined && inRange(k.key, previous[held]) ? held : covering(k.key, previous);
175
+ buckets[home]?.push(k);
176
+ }
177
+ for (const bucket of buckets)
178
+ bucket.sort(order);
179
+ // ⚠ A previous index written by another build may have overlapping ranges, which the format
180
+ // explicitly allows (§6.3.3). Bucketing by range would then interleave keys across chunks, so
181
+ // the placement invariant is checked and a repack that would break it becomes a full repack —
182
+ // slower for one save, and correct.
183
+ if (!ordered(buckets))
184
+ return packAll(entries);
185
+ const reuse = buckets.map((bucket, i) => (unchanged(bucket, previous[i]) ? previous[i]?.h : undefined));
186
+ return close(...merge(...split(buckets, reuse)));
187
+ }
188
+ /** Is this key inside the chunk's declared range? */
189
+ function inRange(key, chunk) {
190
+ if (!chunk)
191
+ return false;
192
+ return comparePlacementKeys(key, chunk.f) >= 0 && comparePlacementKeys(key, chunk.l) <= 0;
193
+ }
194
+ /** The chunk this key belongs to: the last one whose range starts at or before it, else the first. */
195
+ function covering(key, previous) {
196
+ let at = 0;
197
+ for (let i = 0; i < previous.length; i += 1) {
198
+ const f = previous[i]?.f;
199
+ if (f !== undefined && comparePlacementKeys(f, key) <= 0)
200
+ at = i;
201
+ }
202
+ return at;
203
+ }
204
+ /** Do the buckets, read end to end, still hold every entry in placement order? */
205
+ function ordered(buckets) {
206
+ let last = null;
207
+ for (const bucket of buckets) {
208
+ for (const k of bucket) {
209
+ if (last && order(last, k) > 0)
210
+ return false;
211
+ last = k;
212
+ }
213
+ }
214
+ return true;
215
+ }
216
+ /** Same entries, same order, same bytes — the test for "this chunk can keep its name". */
217
+ function unchanged(bucket, chunk) {
218
+ if (!chunk || bucket.length !== chunk.items.length || bucket.length === 0)
219
+ return false;
220
+ for (let i = 0; i < bucket.length; i += 1) {
221
+ const before = chunk.items[i];
222
+ if (!before || before.id !== bucket[i]?.entry.id)
223
+ return false;
224
+ if (JSON.stringify(toWire(before)) !== bucket[i]?.json)
225
+ return false;
226
+ }
227
+ return true;
228
+ }
229
+ /** Split every bucket that outgrew the bound, at the median key, until each one fits. */
230
+ function split(buckets, reuse) {
231
+ const outBuckets = [];
232
+ const outReuse = [];
233
+ for (let i = 0; i < buckets.length; i += 1) {
234
+ const queue = [buckets[i] ?? []];
235
+ let whole = true;
236
+ while (queue.length > 0) {
237
+ const bucket = queue.shift() ?? [];
238
+ if (bucket.length > 1 && sizeOf(bucket) > CHUNK_PLAIN_MAX) {
239
+ const at = Math.floor(bucket.length / 2);
240
+ queue.unshift(bucket.slice(0, at), bucket.slice(at));
241
+ whole = false;
242
+ continue;
243
+ }
244
+ outBuckets.push(bucket);
245
+ outReuse.push(whole ? reuse[i] : undefined);
246
+ }
247
+ }
248
+ return [outBuckets, outReuse];
249
+ }
250
+ /**
251
+ * Merge a chunk that fell under half the bound into the next one, when the pair fits.
252
+ *
253
+ * ⛔ BOTH SIDES HAVE TO BE UNDER HALF, which §6.3.3 does not say and this file adds. Without it a
254
+ * chunk emptied by a delete would pull in a FULL neighbour whenever the two happened to fit, so
255
+ * one removal would rewrite ~4 MiB of somebody else's untouched entries — the opposite of the
256
+ * property chunking exists for. With it, small neighbours combine, a full chunk is never rewritten
257
+ * because of its neighbour, and re-packing a freshly packed list changes nothing (the last chunk
258
+ * is usually the only small one and it has no next).
259
+ *
260
+ * Left to right with the result re-examined, so a run of chunks emptied by a folder delete
261
+ * collapses in one pass instead of leaving a trail of near-empty chunks behind.
262
+ */
263
+ function merge(buckets, reuse) {
264
+ const outBuckets = buckets.map((b) => b.slice());
265
+ const outReuse = reuse.slice();
266
+ const half = CHUNK_PLAIN_MAX / 2;
267
+ let i = 0;
268
+ while (i < outBuckets.length) {
269
+ const here = outBuckets[i] ?? [];
270
+ // A chunk whose every entry left simply stops existing. ⛔ Dropped BEFORE the merge below, or
271
+ // it would be "merged" into its neighbour and cost that neighbour its name for nothing.
272
+ if (here.length === 0) {
273
+ outBuckets.splice(i, 1);
274
+ outReuse.splice(i, 1);
275
+ continue;
276
+ }
277
+ const next = outBuckets[i + 1];
278
+ const fits = next !== undefined && sizeOf(here) + sizeOf(next) - CHUNK_DOC_OVERHEAD <= CHUNK_PLAIN_MAX;
279
+ if (next !== undefined && fits && sizeOf(here) < half && sizeOf(next) < half) {
280
+ outBuckets.splice(i, 2, [...here, ...next]);
281
+ outReuse.splice(i, 2, undefined);
282
+ continue;
283
+ }
284
+ i += 1;
285
+ }
286
+ return [outBuckets, outReuse];
287
+ }
@@ -0,0 +1,113 @@
1
+ export interface AccountSettings {
2
+ /** Developer mode — technical storage facts + ciphertext links in the file detail. Absent = off. */
3
+ developerMode?: true;
4
+ /**
5
+ * In-app text size, percent of the DEVICE's own size. Absent = 100 = follow the device. Never a
6
+ * pixel value: the device's own accessibility setting stays underneath, and this multiplies it.
7
+ */
8
+ textScalePct?: number;
9
+ /**
10
+ * SIZE PADDING rule — how coarsely a file's stored size is rounded up.
11
+ *
12
+ * Absent = Padmé, the default: about 32 possible sizes per doubling, ~1% more storage.
13
+ * `"pow2"` rounds to the next power of two: one size per doubling, ~39% more storage.
14
+ * `"none"` does not round: the file's exact length is what the stored stream states, and about
15
+ * 1% less storage is used. It was added on the owner's rule that anything Walrus itself allows
16
+ * must be reachable here (2026-09-06); the cost of it is stated where the choice is made, which is
17
+ * what makes it a choice rather than a trap.
18
+ *
19
+ * Here, in the sealed list, for the same reason the other two are: the server must not learn it
20
+ * (it would be a per-account fingerprint the server could hold on to), and it
21
+ * follows the account rather than the device, so a phone and a laptop pad the same way.
22
+ *
23
+ * ⚠ It applies to what is uploaded NEXT. Bytes already on the storage network cannot be
24
+ * re-padded, and the screen says so.
25
+ */
26
+ paddingMode?: "pow2" | "none";
27
+ /**
28
+ * DEFAULT DEPOSIT — how many credits ride with each credit-paid upload as its deposit, in whole
29
+ * credits. Absent = the full deposit (`DEPOSIT_MAX_CREDITS`), which is what a person who has
30
+ * never touched this gets. `0` is a real answer and is written: it means "hold nothing back".
31
+ *
32
+ * The deposit pays the network fee when a file is released early; a file with no deposit pays
33
+ * that fee twice, from the balance. The payment screen opens on this number and the person can
34
+ * move it for that one upload.
35
+ *
36
+ * Here, in the sealed list, for the reason the padding rule beside it is: the server must not
37
+ * learn it, and it follows the account, so the browser and the `nmts` command both open on the
38
+ * same figure.
39
+ */
40
+ depositDefault?: number;
41
+ /**
42
+ * STANDING TIP — the share of every storage payment sent to the developer as a gift, in tenths
43
+ * of a percent (25 = 2.5 %). Absent = 0 = nothing is sent. Set by the person, once, on the
44
+ * wallet screen or with the CLI; from then on every payment sends it without a question, in
45
+ * the coin just paid (WAL).
46
+ */
47
+ tipTenths?: number;
48
+ /**
49
+ * When the person first agreed to the gift terms (voluntary · nothing in return · not refundable
50
+ * · goes to the published address · visible on the chain), as a UTC millisecond instant. Absent
51
+ * = never agreed: raising the tip above 0 asks for that agreement once, and later changes do not.
52
+ */
53
+ tipConsentAt?: number;
54
+ }
55
+ /** The sanity bounds a stored text scale must sit in to be USED. One place; codec and UI agree. */
56
+ export declare const TEXT_SCALE_MIN_PCT = 80;
57
+ export declare const TEXT_SCALE_MAX_PCT = 160;
58
+ /** Follow the device. Not written to the wire — absence is the only spelling of it. */
59
+ export declare const TEXT_SCALE_DEFAULT_PCT = 100;
60
+ export interface WireSettings {
61
+ /** developerMode. */
62
+ dm?: 1;
63
+ /** textScalePct. */
64
+ tx?: number;
65
+ /**
66
+ * paddingMode, present only for the non-default rule.
67
+ *
68
+ * ⛔ ADDED 2026-08-24 AFTER MEASURING THAT IT WAS MISSING. The setting existed on
69
+ * `AccountSettings`, the screen wrote it and the uploader read it — but neither direction of
70
+ * this codec carried it, so every save dropped it and every reload went back to the default.
71
+ * Somebody who chose to pay about 39% more storage to round their file sizes more coarsely got
72
+ * the default rule instead, on every device, silently. A settings field is not saved because it
73
+ * is declared; it is saved because both functions below name it.
74
+ */
75
+ pd?: "pow2" | "none";
76
+ /**
77
+ * depositDefault, present only when it is NOT the full deposit.
78
+ *
79
+ * ⚠ `0` is written and read here, unlike every optional field beside it: a person who wants no
80
+ * deposit held has chosen something, and dropping a 0 would silently give them the full 64.
81
+ */
82
+ dd?: number;
83
+ /** tipTenths, present only above 0. */
84
+ tp?: number;
85
+ /** tipConsentAt. */
86
+ tc?: number;
87
+ }
88
+ /** The most a standing tip can be: the whole payment. Above the dial's 10 % it is typed and confirmed. */
89
+ export declare const TIP_TENTHS_MAX = 1000;
90
+ /**
91
+ * The deposit range this format carries: whole credits, 0 to 64.
92
+ *
93
+ * ⚠ The SERVER's own ceiling rides on the account view (`deposit_max`) and is what the payment
94
+ * screen holds the chosen figure inside. This pair is the format's bound, so a value written by
95
+ * some other build is read back only when it is one this build can also write.
96
+ */
97
+ export declare const DEPOSIT_MAX_CREDITS = 64;
98
+ /** What an account's deposit is when nobody chose. Not written to the wire — absence spells it. */
99
+ export declare const DEPOSIT_DEFAULT_CREDITS = 64;
100
+ /** The default deposit in force for an account, in credits. Absence is the full deposit, not 0. */
101
+ export declare function depositDefaultOf(settings: AccountSettings | null | undefined): number;
102
+ /** Settings → wire, or null when every field is at its default (then nothing is written). */
103
+ export declare function settingsToWire(s: AccountSettings | undefined): WireSettings | null;
104
+ /**
105
+ * Wire → settings, dropping anything unusable. A text scale outside the bounds is DROPPED, not
106
+ * clamped: rendering a whole app at a number some other build miswrote is worse than falling back
107
+ * to the device's own size, which is always readable.
108
+ */
109
+ export declare function settingsFromWire(w: unknown): AccountSettings | undefined;
110
+ /** Folds a deposit patch into a settings copy: out-of-range is clamped, the full deposit clears. */
111
+ export declare function applyDepositPatch(next: AccountSettings, depositDefault?: number): void;
112
+ /** Folds a tip patch into a settings copy: 0 clears, above the cap is capped, fractions are rounded. */
113
+ export declare function applyTipPatch(next: AccountSettings, tipTenths?: number, tipConsentAt?: number): void;