@needmoretruth/nmts-cli 0.17.2 → 0.34.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 (419) hide show
  1. package/AGENTS.md +124 -516
  2. package/CHANGELOG.md +98 -0
  3. package/README.ko.md +374 -467
  4. package/README.md +384 -465
  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
@@ -1,4 +1,6 @@
1
- // `nmts push <directory>` — a whole directory, with its shape, paid for with credits.
1
+ // `nmts push <directory>` — a whole directory, with its shape, paid for with credits — or, with
2
+ // `--pay wallet`, each file's storage bought by the person's own wallet (`put-wallet.ts` does one
3
+ // file at a time: its review, its agreement check and its signatures).
2
4
  //
3
5
  // ⛔ IT STOPS AT THE FIRST FAILURE, and that is the opposite of what `pull` does. Pulling costs
4
6
  // nothing, so carrying on past one bad file saves the nineteen good ones. Pushing SPENDS: a
@@ -16,14 +18,14 @@
16
18
  // upload goes to a public storage network. `--hidden` includes them.
17
19
  import { readdirSync, statSync } from "node:fs";
18
20
  import { basename, join, resolve } from "node:path";
19
- import { requireConsent } from "../consent.js";
20
21
  import { DERIVED, loadCrypto } from "../crypto.js";
21
22
  import { normaliseName, normalisePath } from "../drive-paths.js";
22
23
  import { NmtsError } from "../errors.js";
23
24
  import { addEntry } from "../manifest-write.js";
24
25
  import { parseAsked } from "../collision.js";
26
+ import { depositDefaultOf, depositLines, parseDeposit, refuseDepositWithWallet } from "../deposit.js";
25
27
  import { setTrashed } from "../item-trash.js";
26
- import { readFileList } from "../manifest.js";
28
+ import { paddingRuleOf, readFileList } from "../manifest.js";
27
29
  import { BINARY_NAME } from "../product.js";
28
30
  import { Progress, silentSink, stderrSink } from "../progress.js";
29
31
  import { openSession } from "../session.js";
@@ -33,6 +35,7 @@ import { clearItemRecord, clearReservation } from "../upload-store.js";
33
35
  import { CREDIT_BYTES, partSizeFor, planAndPrice, UPLOAD_EPOCHS } from "../upload-price.js";
34
36
  import { createBlobProtocol, readCurrentEpoch } from "../walrus-write.js";
35
37
  import { ensureFolderPath } from "./organise.js";
38
+ import { payerOf, refuseWalletOnlyOptions } from "./put.js";
36
39
  export async function push(target, options = {}) {
37
40
  const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
38
41
  if (target === undefined || target === "") {
@@ -41,6 +44,19 @@ export async function push(target, options = {}) {
41
44
  nextStep: `\`${BINARY_NAME} push <directory>\` — a directory on this machine.`,
42
45
  });
43
46
  }
47
+ const payer = payerOf(options.pay);
48
+ if (payer === "wallet")
49
+ refuseDepositWithWallet(options.deposit);
50
+ if (payer === "credits")
51
+ refuseWalletOnlyOptions(options);
52
+ // ⛔ BEFORE ANYTHING IS WALKED, SEALED OR PAID FOR — a typo must not surface after the money.
53
+ const askedDeposit = parseDeposit(options.deposit);
54
+ if (options.storage !== undefined) {
55
+ throw new NmtsError("--storage is for `put`: a held storage resource holds one blob, and a directory is many.", {
56
+ exitCode: 2,
57
+ nextStep: `Nothing was sent. Leave --storage off to buy new storage for each file.`,
58
+ });
59
+ }
44
60
  const root = resolve(target);
45
61
  let rootStat;
46
62
  try {
@@ -71,7 +87,7 @@ export async function push(target, options = {}) {
71
87
  // ⛔ READ BEFORE ANYTHING IS SEALED OR PAID FOR — a typo must not surface after the money.
72
88
  const asked = parseAsked(options.onCollision);
73
89
  const list = await readFileList(session.server, session.apiKey, session.code, session.accountId);
74
- const rule = list.manifest?.settings?.paddingMode === "pow2" ? "pow2" : "padme";
90
+ const rule = paddingRuleOf(list.manifest?.settings);
75
91
  // ⛔ WHAT IS ALREADY THERE IS DECIDED BEFORE ANYTHING IS PRICED, so the number printed is what
76
92
  // this run will actually spend rather than what a first run would have.
77
93
  const entries = list.manifest?.entries ?? [];
@@ -90,6 +106,14 @@ export async function push(target, options = {}) {
90
106
  }
91
107
  const credits = todo.reduce((sum, one) => sum + planAndPrice(one.size, partSize, rule).credits, 0);
92
108
  const bytes = todo.reduce((sum, one) => sum + one.size, 0);
109
+ // Per FILE, not per run: every file in the tree sets the same amount aside.
110
+ const deposit = askedDeposit ?? depositDefaultOf(list.manifest?.settings);
111
+ if (payer === "wallet") {
112
+ // ⛔ THE WALLET PATH PRICES AND AGREES PER FILE, in `put-wallet.ts`: each file is its own review
113
+ // against the chain's quote, and `--dry-run` prints every review and signs nothing.
114
+ const { pushWithWallet } = await import("./push-wallet.js");
115
+ return await pushWithWallet(session, options, { todo, already, found: found.length, bytes, partSize, rule, asked, settings: list.manifest?.settings, folderIds, say });
116
+ }
93
117
  if (options.dryRun === true) {
94
118
  if (options.json) {
95
119
  say(JSON.stringify({
@@ -98,11 +122,14 @@ export async function push(target, options = {}) {
98
122
  skipped: already.length,
99
123
  bytes,
100
124
  credits,
125
+ deposit,
101
126
  epochs: UPLOAD_EPOCHS,
102
127
  }));
103
128
  return 0;
104
129
  }
105
130
  say(`${todo.length} file${todo.length === 1 ? "" : "s"} ${bytes} bytes → ${credits} credit${credits === 1 ? "" : "s"}`);
131
+ for (const line of depositLines(deposit, todo.length))
132
+ say(line);
106
133
  if (already.length > 0) {
107
134
  say(` ${already.length} already in the drive, which this would not send again`);
108
135
  }
@@ -110,7 +137,6 @@ export async function push(target, options = {}) {
110
137
  say(` Nothing was sent and nothing was charged.`);
111
138
  return 0;
112
139
  }
113
- requireConsent("spend");
114
140
  const progress = new Progress(options.json === true ? silentSink() : stderrSink(), "uploading");
115
141
  const crypt = await loadCrypto();
116
142
  // ⛔ READ ONCE, AND ONLY IF SOMETHING IS ACTUALLY SENT. It is a chain read: a run whose files are
@@ -123,6 +149,8 @@ export async function push(target, options = {}) {
123
149
  };
124
150
  if (!options.json) {
125
151
  say(`${todo.length} file${todo.length === 1 ? "" : "s"} → ${credits} credit${credits === 1 ? "" : "s"}`);
152
+ for (const line of depositLines(deposit, todo.length))
153
+ say(line);
126
154
  if (already.length > 0)
127
155
  say(` ${already.length} already there, not sent again`);
128
156
  }
@@ -138,6 +166,7 @@ export async function push(target, options = {}) {
138
166
  parentId: into,
139
167
  partSize,
140
168
  rule,
169
+ deposit,
141
170
  currentEpoch: await currentEpoch(),
142
171
  progress,
143
172
  }));
@@ -161,7 +190,7 @@ export async function push(target, options = {}) {
161
190
  progress.done();
162
191
  }
163
192
  if (options.json) {
164
- say(JSON.stringify({ files: found.length, uploaded: uploaded.length, skipped: already.length, bytes, credits }));
193
+ say(JSON.stringify({ files: found.length, uploaded: uploaded.length, skipped: already.length, bytes, credits, deposit }));
165
194
  return 0;
166
195
  }
167
196
  say(``);
@@ -189,6 +218,7 @@ async function sendOne(session, crypt, one, ctx) {
189
218
  currentEpoch: ctx.currentEpoch,
190
219
  partSize: ctx.partSize,
191
220
  padding: { rule: ctx.rule, unitBytes: CREDIT_BYTES },
221
+ depositCredits: ctx.deposit,
192
222
  });
193
223
  const now = Date.now();
194
224
  // ⛔ FROM THE RESULT, NOT FROM THIS RUN. The key that opens the stored bytes is the key they
@@ -225,7 +255,7 @@ async function sendOne(session, crypt, one, ctx) {
225
255
  }
226
256
  }
227
257
  /** The folder id for a drive path, made if it is not there yet. Remembered for the next file. */
228
- async function folderFor(session, known, folder) {
258
+ export async function folderFor(session, known, folder) {
229
259
  const held = known.get(folder);
230
260
  if (held !== undefined)
231
261
  return held;
@@ -0,0 +1,77 @@
1
+ import { type OnCollision } from "../collision.ts";
2
+ import { type CryptoGlue } from "../crypto.ts";
3
+ import { type Network } from "../network.ts";
4
+ import { Progress } from "../progress.ts";
5
+ import type { PaddingRule } from "../shared/lib/crypto/size-padding.ts";
6
+ import type { AccountSettings } from "../shared/lib/drive/manifest-settings.ts";
7
+ import type { StandingTipInput } from "../standing-tip.ts";
8
+ import { type WalletUploadReads } from "../upload-wallet-plan.ts";
9
+ import type { BlobProtocol, UploadApi } from "../upload-wire.ts";
10
+ import type { SignBlobCertify, SignBlobRegister } from "../wallet-sign.ts";
11
+ import { type PutOptions } from "./put.ts";
12
+ /** What paying from the wallet adds to an upload command. */
13
+ export interface WalletPayOptions {
14
+ /** How many of the storage network's epochs to buy. Default `DEFAULT_UPLOAD_EPOCHS`. */
15
+ epochs?: string | number | undefined;
16
+ /** `fit`, `whole`, or a held resource's object id. Absent = buy new storage. */
17
+ storage?: string | undefined;
18
+ /** The instant the wallet agreement is measured against. */
19
+ now?: number;
20
+ /** ⚠ A SEAM, NOT AN OPTION — no flag reaches it. */
21
+ readChain?: (network: Network, relayUrl: string) => WalletUploadReads | Promise<WalletUploadReads>;
22
+ /** ⛔ SEPARATE FROM THE READS so a test can prove the review stops before this. */
23
+ sign?: {
24
+ register: SignBlobRegister;
25
+ certify: SignBlobCertify;
26
+ };
27
+ /** ⚠ SEAMS, NOT OPTIONS — the standing tip's own read and signature. No flag reaches them. */
28
+ tip?: Pick<StandingTipInput, "readDonation" | "sign">;
29
+ /** The storage-network protocol and the server calls — seams for the tests, as `upload.ts` has. */
30
+ protocol?: (network: Network, bodyBytes: number, onSent: (sent: number, total: number) => void) => BlobProtocol & {
31
+ relayUrl: string;
32
+ };
33
+ api?: UploadApi;
34
+ }
35
+ export type PutWalletOptions = PutOptions & WalletPayOptions;
36
+ /** One local file and where it goes — what `put` and `push` both hand in. */
37
+ export interface WalletUploadFile {
38
+ localPath: string;
39
+ size: number;
40
+ name: string;
41
+ parentId: string | null;
42
+ /** The destination AS TYPED — part of the reservation key. */
43
+ destination: string;
44
+ }
45
+ export interface WalletUploadContext {
46
+ code: string;
47
+ apiKey: string;
48
+ server: string;
49
+ network: Network;
50
+ accountId: string;
51
+ crypt: CryptoGlue;
52
+ partSize: number;
53
+ rule: PaddingRule;
54
+ onCollision?: OnCollision | undefined;
55
+ /** The sealed list's account settings, as read for this run — the standing tip lives in them. */
56
+ settings?: AccountSettings | undefined;
57
+ progress: Progress;
58
+ say: (line: string) => void;
59
+ json: boolean;
60
+ }
61
+ export declare function putWithWallet(target: string | undefined, options: PutWalletOptions): Promise<number>;
62
+ /**
63
+ * Review, agree, upload and record ONE file. Null when `--dry-run` stopped at the review.
64
+ *
65
+ * ⛔ THE SIGNING MODULE IS LOADED AFTER THE AGREEMENT, and only then — a dry run and a refusal
66
+ * never bring the code that can spend into memory.
67
+ */
68
+ export declare function uploadOneWithWallet(ctx: WalletUploadContext, file: WalletUploadFile, options: WalletPayOptions & {
69
+ dryRun?: boolean | undefined;
70
+ }): Promise<{
71
+ itemId: string;
72
+ savedAs: string;
73
+ replaced: string | null;
74
+ seq: number;
75
+ resumed: boolean;
76
+ facts: Record<string, unknown>;
77
+ } | null>;
@@ -0,0 +1,316 @@
1
+ // `nmts put <file> --pay wallet` — one file in, sealed on this machine, its storage bought by the
2
+ // PERSON'S OWN WALLET on the storage network instead of by credits.
3
+ //
4
+ // ⛔ IT PRICES BEFORE IT SIGNS, ALWAYS, in the order `extend` set: the parts are planned, the chain
5
+ // quotes each part in WAL and the relay's tip in SUI, the register transaction is dry-run for
6
+ // its fee, both balances are read — and only then is the review printed, a known shortfall
7
+ // refused, and the `wallet` agreement (scope `storage`) held against the total. `--dry-run`
8
+ // stops at the review and never loads the signing module.
9
+ //
10
+ // ⛔ THE SERVER IS TOLD THE STORAGE IS THE PERSON'S BY SAYING NOTHING ELSE. `POST /v1/items` forces
11
+ // treasury ownership only on a part that names a certified reservation; a wallet-paid part names
12
+ // none and carries the blob object and the end epoch instead, exactly as the browser's own
13
+ // wallet-paid commit does (`upload-steps.ts`).
14
+ //
15
+ // ⛔ A HELD RESOURCE IS OFFERED, NEVER CHOSEN FOR THE PERSON — the owner's rule for storage
16
+ // resources: the leftover is shown in bytes and the person decides. The review names how many
17
+ // free resources the wallet holds; `--storage fit|whole|<id>` uses one and the review says in
18
+ // bytes what is cut free or bound with the file.
19
+ import { basename, resolve } from "node:path";
20
+ import { identityOf } from "../account.js";
21
+ import { requireAccountCode } from "../code-access.js";
22
+ import { parseAsked } from "../collision.js";
23
+ import { DERIVED, loadCrypto } from "../crypto.js";
24
+ import { API_KEY_ENV_VAR, readCredentialsFile, resolveApiKey } from "../credentials.js";
25
+ import { NmtsError } from "../errors.js";
26
+ import { setTrashed } from "../item-trash.js";
27
+ import { addEntry } from "../manifest-write.js";
28
+ import { paddingRuleOf, readFileList } from "../manifest.js";
29
+ import { resolveNetwork } from "../network.js";
30
+ import { BINARY_NAME } from "../product.js";
31
+ import { Progress, silentSink, stderrSink } from "../progress.js";
32
+ import { sealedLenFor } from "../seal.js";
33
+ import { resolveServer } from "../server.js";
34
+ import { statusOf } from "../shared/lib/storage-control/plan.js";
35
+ import { createUploadApi } from "../upload-api.js";
36
+ import { fileSource, partKeysOf, uploadFile } from "../upload-file.js";
37
+ import { CREDIT_BYTES, measureLocal, partSizeFor, planAndPrice } from "../upload-price.js";
38
+ import { clearItemRecord, clearReservation } from "../upload-store.js";
39
+ import { walletRail } from "../upload-wallet.js";
40
+ import { chooseUploadEpochs, daysOf, describeUploadReview, parseStorageAsk, pickResource, uploadBudget, uploadShortfallNextStep, walPrice, } from "../upload-wallet-plan.js";
41
+ import { coinAmount, walletAddress } from "../wallet.js";
42
+ import { recordWalletSpend, requireWalletGrant } from "../wallet-grant.js";
43
+ import { createBlobProtocol } from "../walrus-write.js";
44
+ import { folderIdFor } from "./put.js";
45
+ export async function putWithWallet(target, options) {
46
+ const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
47
+ if (target === undefined || target === "") {
48
+ throw new NmtsError("Say which file to put.", { exitCode: 2, nextStep: `\`${BINARY_NAME} put <file> --pay wallet\`` });
49
+ }
50
+ const resolved = await requireAccountCode();
51
+ const key = resolveApiKey();
52
+ if (key === null) {
53
+ throw new NmtsError("This account has no API key on this machine, and the server needs one.", {
54
+ exitCode: 3,
55
+ nextStep: `Make a key on the account screen at nmts.me and put it in ${API_KEY_ENV_VAR}, or store it with \`${BINARY_NAME} login\`.`,
56
+ });
57
+ }
58
+ const localPath = resolve(target);
59
+ const size = measureLocal(localPath);
60
+ const stored = readCredentialsFile();
61
+ const server = resolveServer(options.server ?? stored?.server);
62
+ const network = resolveNetwork(server, options.network ?? stored?.network);
63
+ const identity = await identityOf(resolved.code);
64
+ const crypt = await loadCrypto();
65
+ const asked = parseAsked(options.onCollision);
66
+ const list = await readFileList(server, key.key, resolved.code, identity.accountId);
67
+ const rule = paddingRuleOf(list.manifest?.settings);
68
+ const name = options.name ?? basename(localPath);
69
+ const destination = (options.to ?? "").replace(/^\.?\//, "").replace(/\/$/, "");
70
+ const parentId = folderIdFor(options.to, list.manifest?.entries ?? []);
71
+ const ctx = {
72
+ code: resolved.code,
73
+ apiKey: key.key,
74
+ server,
75
+ network,
76
+ accountId: identity.accountId,
77
+ crypt,
78
+ partSize: partSizeFor(options.partSize),
79
+ rule,
80
+ onCollision: asked,
81
+ settings: list.manifest?.settings,
82
+ progress: new Progress(options.json === true ? silentSink() : stderrSink(), "uploading"),
83
+ say,
84
+ json: options.json === true,
85
+ };
86
+ const done = await uploadOneWithWallet(ctx, { localPath, size, name, parentId, destination }, options);
87
+ if (done === null)
88
+ return 0;
89
+ if (options.json) {
90
+ say(JSON.stringify({ id: done.itemId, name: done.savedAs, ...done.facts, resumed: done.resumed, renamed: done.savedAs !== name, ...(done.replaced ? { replacedIntoTrash: done.replaced } : {}), fileListVersion: done.seq }));
91
+ return 0;
92
+ }
93
+ say(` saved as ${done.savedAs}`);
94
+ if (done.replaced)
95
+ say(` A file called ${name} was already there. It is in the trash now — ${BINARY_NAME} restore brings it back for 30 days.`);
96
+ else if (done.savedAs !== name)
97
+ say(` A file called ${name} was already there, so this one was numbered rather than replacing it.`);
98
+ if (done.resumed)
99
+ say(` This finished an upload a previous run had already signed for. Nothing was signed now.`);
100
+ return 0;
101
+ }
102
+ /**
103
+ * Review, agree, upload and record ONE file. Null when `--dry-run` stopped at the review.
104
+ *
105
+ * ⛔ THE SIGNING MODULE IS LOADED AFTER THE AGREEMENT, and only then — a dry run and a refusal
106
+ * never bring the code that can spend into memory.
107
+ */
108
+ export async function uploadOneWithWallet(ctx, file, options) {
109
+ const { say } = ctx;
110
+ const { plan, sealedBytes, sealFor } = planAndPrice(file.size, ctx.partSize, ctx.rule);
111
+ const sealedLens = plan.map((range) => sealedLenFor(sealFor(range)));
112
+ const storageAsk = parseStorageAsk(options.storage);
113
+ if (storageAsk !== null && plan.length > 1) {
114
+ throw new NmtsError(`A held storage resource holds one blob, and this file is ${plan.length} parts.`, {
115
+ exitCode: 4,
116
+ nextStep: `Nothing was signed. Leave --storage off, or raise --part-size so the file is one part.`,
117
+ });
118
+ }
119
+ const protocol = (options.protocol ?? createBlobProtocol)(ctx.network, sealedBytes, (sent, total) => ctx.progress.update(sent, total));
120
+ const reads = await (options.readChain ?? defaultReads)(ctx.network, protocol.relayUrl);
121
+ const window = await reads.readWindow();
122
+ if (window === null) {
123
+ throw new NmtsError(`The ${ctx.network} storage network could not be read.`, {
124
+ exitCode: 1,
125
+ nextStep: `Nothing was signed and nothing was sent. Which epoch the network is in, and how far ahead it will sell, are facts only the chain has — this tool will not spend against a guess.`,
126
+ });
127
+ }
128
+ const epochs = chooseUploadEpochs(options.epochs, window);
129
+ const endEpoch = window.clock.current + epochs;
130
+ const quotes = await reads.quoteParts(sealedLens, epochs);
131
+ const address = await walletAddress(ctx.code);
132
+ let storage = { kind: "buy" };
133
+ let heldResources = null;
134
+ if (storageAsk !== null) {
135
+ const firstQuote = quotes[0];
136
+ const firstLen = sealedLens[0];
137
+ if (firstQuote === undefined || firstLen === undefined)
138
+ throw new NmtsError("unreachable: a plan with no part");
139
+ let resources;
140
+ try {
141
+ resources = await reads.readStorage(address);
142
+ }
143
+ catch (error) {
144
+ throw new NmtsError("The storage resources this wallet holds could not be read.", {
145
+ exitCode: 1,
146
+ nextStep: `Nothing was signed. That is not the same as holding none. Cause: ${error instanceof Error ? error.message : String(error)}`,
147
+ });
148
+ }
149
+ const encoded = await reads.encodedLength(address, firstLen);
150
+ storage = pickResource(storageAsk, resources, encoded, window.clock.current, endEpoch, firstQuote.writeFrost);
151
+ }
152
+ else {
153
+ heldResources = await reads.readStorage(address).then((rows) => rows.filter((r) => statusOf(r, window.clock.current) === "usable").length, () => null);
154
+ }
155
+ const [purse, feeMist] = await Promise.all([
156
+ reads.readWallet(address),
157
+ reads.estimateRegisterGas({
158
+ sender: address,
159
+ sealedLen: Math.max(...sealedLens),
160
+ epochs,
161
+ storage: storage.kind === "buy" ? storage : { kind: "reuse", objectId: storage.objectId, cutToBytes: storage.cutToBytes, writeFrost: storage.writeFrost },
162
+ }),
163
+ ]);
164
+ const budget = uploadBudget({ address, purse, feeMist, quotes, storage });
165
+ const tipMist = quotes.reduce((sum, q) => sum + q.tipMist, 0n);
166
+ const facts = {
167
+ bytes: file.size,
168
+ sealedBytes,
169
+ parts: plan.length,
170
+ epochs,
171
+ days: daysOf(window, epochs),
172
+ endEpoch,
173
+ paidFrom: "wallet",
174
+ priceFrost: budget.walNeededFrost.toString(),
175
+ priceWal: coinAmount(budget.walNeededFrost),
176
+ tipMist: tipMist.toString(),
177
+ tipSui: coinAmount(tipMist),
178
+ feeMist: feeMist === null ? null : feeMist.toString(),
179
+ feeSui: feeMist === null ? null : coinAmount(feeMist),
180
+ wallet: address,
181
+ walletWal: budget.walFrost === null ? null : coinAmount(budget.walFrost),
182
+ walletSui: budget.suiMist === null ? null : coinAmount(budget.suiMist),
183
+ storage: storage.kind === "buy"
184
+ ? { kind: "buy" }
185
+ : { kind: "reuse", objectId: storage.objectId, cutToBytes: storage.cutToBytes, leftoverBytes: storage.leftoverBytes },
186
+ };
187
+ if (!ctx.json) {
188
+ describeUploadReview(say, { name: file.name, bytes: file.size, parts: plan.length, epochs, days: daysOf(window, epochs), endEpoch, walNeeded: walPrice(quotes, storage), tipMist, storage, heldResources }, budget);
189
+ }
190
+ if (options.dryRun === true) {
191
+ if (ctx.json)
192
+ say(JSON.stringify({ dryRun: true, name: file.name, ...facts, signed: false }));
193
+ else {
194
+ say(``);
195
+ if (budget.shortfall !== null)
196
+ say(` ⚠ ${budget.shortfall} As it stands, it would be refused.`);
197
+ say(` Nothing was signed and nothing was sent. Run the same command without --dry-run to upload it.`);
198
+ }
199
+ return null;
200
+ }
201
+ // ⛔ A WALLET KNOWN TO BE SHORT IS REFUSED BEFORE THE AGREEMENT IS ASKED FOR (`extend-budget.ts`).
202
+ if (budget.shortfall !== null) {
203
+ throw new NmtsError(budget.shortfall, { exitCode: 4, nextStep: uploadShortfallNextStep(budget) });
204
+ }
205
+ // ⛔ THE ONE GATE BETWEEN A PROGRAM AND SOMEBODY'S WALLET. Everything above is a read.
206
+ requireWalletGrant("seal", { walFrost: budget.walNeededFrost, suiMist: budget.suiNeededMist }, new Date(options.now ?? Date.now()));
207
+ const sign = options.sign ?? (await signers());
208
+ const derived = ctx.crypt.kdf_derive(ctx.crypt.account_code_parse(ctx.code));
209
+ const dataKey = derived.slice(DERIVED.dataKey[0], DERIVED.dataKey[1]);
210
+ derived.fill(0);
211
+ let result;
212
+ try {
213
+ result = await uploadFile({
214
+ api: options.api ?? createUploadApi(ctx.server, ctx.apiKey),
215
+ protocol,
216
+ crypt: ctx.crypt,
217
+ dataKey,
218
+ source: fileSource(file.localPath, file.size),
219
+ name: file.name,
220
+ parentId: file.parentId,
221
+ destination: file.destination,
222
+ relayUrl: protocol.relayUrl,
223
+ epochs,
224
+ currentEpoch: window.clock.current,
225
+ partSize: ctx.partSize,
226
+ padding: { rule: ctx.rule, unitBytes: CREDIT_BYTES },
227
+ onStep: (step) => tell(ctx, file.size, step),
228
+ buy: walletRail({
229
+ network: ctx.network,
230
+ code: ctx.code,
231
+ relayUrl: protocol.relayUrl,
232
+ epochs,
233
+ storage,
234
+ quotes,
235
+ feeMist,
236
+ signRegister: sign.register,
237
+ signCertify: sign.certify,
238
+ onSpend: recordWalletSpend,
239
+ }),
240
+ });
241
+ }
242
+ finally {
243
+ ctx.progress.done();
244
+ dataKey.fill(0);
245
+ }
246
+ const now = Date.now();
247
+ const added = await addEntry({
248
+ server: ctx.server,
249
+ apiKey: ctx.apiKey,
250
+ code: ctx.code,
251
+ accountId: ctx.accountId,
252
+ ...(ctx.onCollision !== undefined ? { onCollision: ctx.onCollision } : {}),
253
+ entry: {
254
+ id: result.itemId,
255
+ parentId: file.parentId,
256
+ kind: 1,
257
+ name: result.entry.name,
258
+ size: result.entry.plaintextLen,
259
+ createdAt: now,
260
+ updatedAt: now,
261
+ dekWrapped: result.entry.dekWrapped,
262
+ contentHashCt: result.entry.contentHashCt,
263
+ },
264
+ });
265
+ // ⛔ ONLY NOW, AND EVERY PART — the same order `put.ts` keeps and for the same reason.
266
+ clearItemRecord(result.fileKey);
267
+ for (const record of partKeysOf(result.fileKey, result.parts))
268
+ clearReservation(record);
269
+ if (added.replaced)
270
+ await setTrashed(ctx.server, ctx.apiKey, added.replaced.id, true);
271
+ // ⛔ THE STANDING SHARE, AFTER THE PAYMENT AND NEVER INSIDE IT: a gift that fails must not fail
272
+ // the upload. A resumed run paid nothing now, so it owes nothing now. In --json the tip speaks
273
+ // on stderr — stdout carries the machine's one answer and nothing else.
274
+ await (await import("../standing-tip.js")).standingTipAfter({
275
+ server: ctx.server,
276
+ network: ctx.network,
277
+ code: ctx.code,
278
+ settings: ctx.settings,
279
+ paidWalFrost: result.resumed ? 0n : budget.walNeededFrost,
280
+ say: ctx.json ? (line) => void process.stderr.write(`${line}\n`) : say,
281
+ ...(options.tip ?? {}),
282
+ });
283
+ return { itemId: result.itemId, savedAs: added.name, replaced: added.replaced?.id ?? null, seq: added.seq, resumed: result.resumed, facts };
284
+ }
285
+ /** Each step, for a person watching. The signatures are named as what they are. */
286
+ function tell(ctx, size, step) {
287
+ if (ctx.json || step.step === "planning")
288
+ return;
289
+ const { say } = ctx;
290
+ if (step.step === "hashing")
291
+ return say(` reading ${size} bytes`);
292
+ const where = step.parts > 1 ? ` [${step.partIndex + 1}/${step.parts}]` : "";
293
+ if (step.step === "sealing")
294
+ say(` sealing${where} ${step.bytes} bytes`);
295
+ if (step.step === "resuming")
296
+ say(` picking up a part already ${step.state}${where}`);
297
+ if (step.step === "encoding")
298
+ say(` preparing${where} ${step.bytes} sealed bytes`);
299
+ if (step.step === "reserving")
300
+ say(` signing the registration${where} — WAL and the relay tip leave the wallet`);
301
+ if (step.step === "uploading")
302
+ say(` uploading${where} ${step.bytes} bytes to ${step.relayUrl}`);
303
+ if (step.step === "certifying") {
304
+ ctx.progress.done();
305
+ say(` signing the certification${where} — gas only`);
306
+ }
307
+ if (step.step === "committing")
308
+ say(` saving to the drive`);
309
+ }
310
+ async function defaultReads(network, relayUrl) {
311
+ return (await import("../upload-wallet-chain.js")).walletUploadReads(network, relayUrl);
312
+ }
313
+ async function signers() {
314
+ const signing = await import("../wallet-sign.js");
315
+ return { register: signing.signBlobRegister, certify: signing.signBlobCertify };
316
+ }
@@ -0,0 +1,56 @@
1
+ import type { ManifestEntry } from "../shared/lib/drive/manifest-codec.ts";
2
+ export interface PutOptions {
3
+ server?: string | undefined;
4
+ network?: string | undefined;
5
+ /** The name it gets in the drive. Defaults to the local file's own name. */
6
+ name?: string | undefined;
7
+ /** Destination folder, as `nmts ls` prints it. The drive root when absent. */
8
+ to?: string | undefined;
9
+ /** Say what it would cost and stop. Nothing is sealed, sent, or charged. */
10
+ dryRun?: boolean;
11
+ /**
12
+ * How much of the file goes into one part, in bytes. Defaults to `DEFAULT_PART_BYTES`.
13
+ *
14
+ * Bigger parts mean fewer reservations, and every reservation counts against the account's
15
+ * daily spending allowance; smaller parts mean less memory and a shorter piece of work to lose
16
+ * when something goes wrong. An exact number, not a menu — a person who knows what their machine
17
+ * can hold should be able to say so.
18
+ */
19
+ partSize?: string | number | undefined;
20
+ /** What THIS run does about a name already in use. Absent = this machine's setting. */
21
+ onCollision?: string | undefined;
22
+ /**
23
+ * How many credits THIS upload sets aside as a deposit on the file, 0 to 64. Absent = the
24
+ * account's own default (`nmts deposit`), which is 64 until somebody sets another.
25
+ */
26
+ deposit?: string | number | undefined;
27
+ /**
28
+ * Who pays for the storage: `credits` (absent) or `wallet`.
29
+ *
30
+ * ⛔ A VALUE, NOT A FLAG, so that a command line says which money it spends. Everything about the
31
+ * wallet path — the epochs, the review, the agreement, the signatures — is in `put-wallet.ts`.
32
+ */
33
+ pay?: string | undefined;
34
+ /** `--pay wallet`: how many epochs to buy. Refused with credits, whose term is fixed. */
35
+ epochs?: string | number | undefined;
36
+ /** `--pay wallet`: a held storage resource to use — `fit`, `whole`, or its object id. */
37
+ storage?: string | undefined;
38
+ json?: boolean;
39
+ write?: (line: string) => void;
40
+ }
41
+ /** Who pays, or a refusal for a payer this tool does not know. */
42
+ export declare function payerOf(pay: string | undefined): "credits" | "wallet";
43
+ /** The two options that only mean something when the wallet pays, refused when it does not. */
44
+ export declare function refuseWalletOnlyOptions(options: {
45
+ epochs?: string | number | undefined;
46
+ storage?: string | undefined;
47
+ }): void;
48
+ /**
49
+ * The folder id `--to` names, or null for the root. Refuses rather than guessing.
50
+ *
51
+ * ⛔ IT IS THE SAME LOOKUP EVERY OTHER COMMAND USES. This had its own walk and its own
52
+ * `e.deletedAt` test, which meant it would happily accept a folder whose PARENT was in the
53
+ * trash and put a paid-for upload somewhere the drive does not show (2026-08-23).
54
+ */
55
+ export declare function folderIdFor(wanted: string | undefined, entries: readonly ManifestEntry[]): string | null;
56
+ export declare function put(target: string | undefined, options?: PutOptions): Promise<number>;