@defdone/annon 0.0.0-stage → 0.1.0-alpha.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 (214) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/CLI.md +378 -0
  3. package/LICENSE +201 -0
  4. package/NOTICE +7 -0
  5. package/README.md +591 -2
  6. package/dist/api/annon-types.d.ts +108 -0
  7. package/dist/api/annon-types.js +2 -0
  8. package/dist/api/annon.d.ts +117 -0
  9. package/dist/api/annon.js +1152 -0
  10. package/dist/api/hosted-record.d.ts +13 -0
  11. package/dist/api/hosted-record.js +149 -0
  12. package/dist/api/sharing-types.d.ts +109 -0
  13. package/dist/api/sharing-types.js +1 -0
  14. package/dist/api/sharing.d.ts +36 -0
  15. package/dist/api/sharing.js +879 -0
  16. package/dist/browser/download.d.ts +19 -0
  17. package/dist/browser/download.js +52 -0
  18. package/dist/browser/index.d.ts +23 -0
  19. package/dist/browser/index.js +22 -0
  20. package/dist/browser/login-bundle.js +151 -0
  21. package/dist/browser/login.d.ts +1 -0
  22. package/dist/browser/login.js +216 -0
  23. package/dist/browser/purchase-bundle.js +84 -0
  24. package/dist/browser/purchases.d.ts +98 -0
  25. package/dist/browser/purchases.js +735 -0
  26. package/dist/browser/record.d.ts +55 -0
  27. package/dist/browser/record.js +16 -0
  28. package/dist/browser/selling.d.ts +146 -0
  29. package/dist/browser/selling.js +418 -0
  30. package/dist/browser/wallets.d.ts +53 -0
  31. package/dist/browser/wallets.js +286 -0
  32. package/dist/bytes.d.ts +4 -0
  33. package/dist/bytes.js +16 -0
  34. package/dist/download/download.d.ts +59 -0
  35. package/dist/download/download.js +384 -0
  36. package/dist/download/host.d.ts +56 -0
  37. package/dist/download/host.js +161 -0
  38. package/dist/download/http.d.ts +23 -0
  39. package/dist/download/http.js +87 -0
  40. package/dist/download/proof.d.ts +20 -0
  41. package/dist/download/proof.js +79 -0
  42. package/dist/download/upload.d.ts +130 -0
  43. package/dist/download/upload.js +408 -0
  44. package/dist/envelope/evm.d.ts +4 -0
  45. package/dist/envelope/evm.js +32 -0
  46. package/dist/envelope/pay2.d.ts +176 -0
  47. package/dist/envelope/pay2.js +541 -0
  48. package/dist/envelope/replay.d.ts +45 -0
  49. package/dist/envelope/replay.js +186 -0
  50. package/dist/envelope/stream.d.ts +78 -0
  51. package/dist/envelope/stream.js +372 -0
  52. package/dist/errors.d.ts +21 -0
  53. package/dist/errors.js +300 -0
  54. package/dist/index.d.ts +25 -0
  55. package/dist/index.js +23 -0
  56. package/dist/keys/near-ckd.d.ts +47 -0
  57. package/dist/keys/near-ckd.js +96 -0
  58. package/dist/limits.d.ts +4 -0
  59. package/dist/limits.js +4 -0
  60. package/dist/near/nep413.d.ts +22 -0
  61. package/dist/near/nep413.js +39 -0
  62. package/dist/near/rpc.d.ts +170 -0
  63. package/dist/near/rpc.js +423 -0
  64. package/dist/near/texts.d.ts +39 -0
  65. package/dist/near/texts.js +60 -0
  66. package/dist/net/ip.d.ts +7 -0
  67. package/dist/net/ip.js +62 -0
  68. package/dist/net/retry.d.ts +3 -0
  69. package/dist/net/retry.js +31 -0
  70. package/dist/node/adapter-checks.d.ts +6 -0
  71. package/dist/node/adapter-checks.js +13 -0
  72. package/dist/node/adapter.d.ts +8 -0
  73. package/dist/node/adapter.js +98 -0
  74. package/dist/node/agent.d.ts +49 -0
  75. package/dist/node/agent.js +266 -0
  76. package/dist/node/amounts.d.ts +2 -0
  77. package/dist/node/amounts.js +20 -0
  78. package/dist/node/browser-login.d.ts +25 -0
  79. package/dist/node/browser-login.js +219 -0
  80. package/dist/node/budget.d.ts +24 -0
  81. package/dist/node/budget.js +59 -0
  82. package/dist/node/buy-commands.d.ts +24 -0
  83. package/dist/node/buy-commands.js +301 -0
  84. package/dist/node/cli.d.ts +60 -0
  85. package/dist/node/cli.js +201 -0
  86. package/dist/node/command-context.d.ts +82 -0
  87. package/dist/node/command-context.js +77 -0
  88. package/dist/node/config.d.ts +37 -0
  89. package/dist/node/config.js +189 -0
  90. package/dist/node/core-adapter.d.ts +43 -0
  91. package/dist/node/core-adapter.js +122 -0
  92. package/dist/node/errors.d.ts +8 -0
  93. package/dist/node/errors.js +12 -0
  94. package/dist/node/index.d.ts +7 -0
  95. package/dist/node/index.js +5 -0
  96. package/dist/node/io.d.ts +13 -0
  97. package/dist/node/io.js +112 -0
  98. package/dist/node/keychain.d.ts +10 -0
  99. package/dist/node/keychain.js +67 -0
  100. package/dist/node/main.d.ts +2 -0
  101. package/dist/node/main.js +21 -0
  102. package/dist/node/offers.d.ts +16 -0
  103. package/dist/node/offers.js +91 -0
  104. package/dist/node/origin.d.ts +11 -0
  105. package/dist/node/origin.js +80 -0
  106. package/dist/node/paths.d.ts +3 -0
  107. package/dist/node/paths.js +71 -0
  108. package/dist/node/payment-terms.d.ts +26 -0
  109. package/dist/node/payment-terms.js +127 -0
  110. package/dist/node/purchase-commands.d.ts +16 -0
  111. package/dist/node/purchase-commands.js +237 -0
  112. package/dist/node/purchase-guard.d.ts +19 -0
  113. package/dist/node/purchase-guard.js +53 -0
  114. package/dist/node/relay-transport.d.ts +6 -0
  115. package/dist/node/relay-transport.js +173 -0
  116. package/dist/node/resources.d.ts +2 -0
  117. package/dist/node/resources.js +26 -0
  118. package/dist/node/retry-gate.d.ts +15 -0
  119. package/dist/node/retry-gate.js +53 -0
  120. package/dist/node/seller-commands.d.ts +12 -0
  121. package/dist/node/seller-commands.js +207 -0
  122. package/dist/node/sharing.d.ts +3 -0
  123. package/dist/node/sharing.js +28 -0
  124. package/dist/node/shops.d.ts +17 -0
  125. package/dist/node/shops.js +74 -0
  126. package/dist/node/signer-mock.d.ts +11 -0
  127. package/dist/node/signer-mock.js +79 -0
  128. package/dist/node/signer-wallet.d.ts +8 -0
  129. package/dist/node/signer-wallet.js +149 -0
  130. package/dist/node/signing.d.ts +29 -0
  131. package/dist/node/signing.js +200 -0
  132. package/dist/node/storage-commands.d.ts +11 -0
  133. package/dist/node/storage-commands.js +50 -0
  134. package/dist/node/sync-dir.d.ts +1 -0
  135. package/dist/node/sync-dir.js +11 -0
  136. package/dist/node/wallets.d.ts +13 -0
  137. package/dist/node/wallets.js +146 -0
  138. package/dist/oneclick/oneclick.d.ts +132 -0
  139. package/dist/oneclick/oneclick.js +342 -0
  140. package/dist/pay/backup.d.ts +70 -0
  141. package/dist/pay/backup.js +402 -0
  142. package/dist/pay/base.d.ts +135 -0
  143. package/dist/pay/base.js +386 -0
  144. package/dist/pay/eip3009.d.ts +59 -0
  145. package/dist/pay/eip3009.js +72 -0
  146. package/dist/pay/pay.d.ts +86 -0
  147. package/dist/pay/pay.js +297 -0
  148. package/dist/pay/purchase.d.ts +103 -0
  149. package/dist/pay/purchase.js +20 -0
  150. package/dist/pay/recover.d.ts +31 -0
  151. package/dist/pay/recover.js +34 -0
  152. package/dist/pay/seller.d.ts +130 -0
  153. package/dist/pay/seller.js +444 -0
  154. package/dist/pay/settle.d.ts +96 -0
  155. package/dist/pay/settle.js +308 -0
  156. package/dist/pay/split.d.ts +115 -0
  157. package/dist/pay/split.js +256 -0
  158. package/dist/pay/store-node.d.ts +8 -0
  159. package/dist/pay/store-node.js +224 -0
  160. package/dist/pay/store.d.ts +54 -0
  161. package/dist/pay/store.js +135 -0
  162. package/dist/pay/x402.d.ts +95 -0
  163. package/dist/pay/x402.js +136 -0
  164. package/dist/relay/admission.d.ts +8 -0
  165. package/dist/relay/admission.js +58 -0
  166. package/dist/relay/capabilities.d.ts +36 -0
  167. package/dist/relay/capabilities.js +232 -0
  168. package/dist/relay/fees.d.ts +17 -0
  169. package/dist/relay/fees.js +105 -0
  170. package/dist/relay/index.d.ts +10 -0
  171. package/dist/relay/index.js +8 -0
  172. package/dist/relay/keeper-balance.d.ts +17 -0
  173. package/dist/relay/keeper-balance.js +46 -0
  174. package/dist/relay/keeper-runner.d.ts +114 -0
  175. package/dist/relay/keeper-runner.js +703 -0
  176. package/dist/relay/keeper.d.ts +38 -0
  177. package/dist/relay/keeper.js +73 -0
  178. package/dist/relay/ledger.d.ts +155 -0
  179. package/dist/relay/ledger.js +392 -0
  180. package/dist/relay/relay-checks.d.ts +3 -0
  181. package/dist/relay/relay-checks.js +244 -0
  182. package/dist/relay/relay-reconciliation.d.ts +15 -0
  183. package/dist/relay/relay-reconciliation.js +293 -0
  184. package/dist/relay/relay-request.d.ts +6 -0
  185. package/dist/relay/relay-request.js +139 -0
  186. package/dist/relay/relay-transactions.d.ts +23 -0
  187. package/dist/relay/relay-transactions.js +182 -0
  188. package/dist/relay/relay-types.d.ts +128 -0
  189. package/dist/relay/relay-types.js +17 -0
  190. package/dist/relay/relay.d.ts +102 -0
  191. package/dist/relay/relay.js +426 -0
  192. package/dist/relay/reservation.d.ts +29 -0
  193. package/dist/relay/reservation.js +132 -0
  194. package/dist/relay/sponsorship.d.ts +42 -0
  195. package/dist/relay/sponsorship.js +184 -0
  196. package/dist/routes.d.ts +2 -0
  197. package/dist/routes.js +1 -0
  198. package/dist/settle-near/codec.d.ts +17 -0
  199. package/dist/settle-near/codec.js +86 -0
  200. package/dist/settle-near/identity.d.ts +27 -0
  201. package/dist/settle-near/identity.js +80 -0
  202. package/dist/settle-near/purchase.d.ts +40 -0
  203. package/dist/settle-near/purchase.js +153 -0
  204. package/dist/settle-near/terms.d.ts +37 -0
  205. package/dist/settle-near/terms.js +89 -0
  206. package/dist/shops/discovery.d.ts +95 -0
  207. package/dist/shops/discovery.js +384 -0
  208. package/dist/wallet/account-only.d.ts +11 -0
  209. package/dist/wallet/account-only.js +6 -0
  210. package/dist/wallet/uncertain.d.ts +8 -0
  211. package/dist/wallet/uncertain.js +13 -0
  212. package/dist/wallet/wallet.d.ts +100 -0
  213. package/dist/wallet/wallet.js +204 -0
  214. package/package.json +136 -3
package/dist/errors.js ADDED
@@ -0,0 +1,300 @@
1
+ /** Browser-safe public failures. Upstream diagnostics never cross a public boundary. */
2
+ export const annonErrorCodes = [
3
+ 'invalid_arguments',
4
+ 'invalid_config',
5
+ 'invalid_record',
6
+ 'config_conflict',
7
+ 'agent_policy',
8
+ 'human_only',
9
+ 'confirmation_required',
10
+ 'sale_not_approved',
11
+ 'trust_required',
12
+ 'signer_required',
13
+ 'signer_init_only',
14
+ 'credentials_required',
15
+ 'backup_secret_required',
16
+ 'work_dir_required',
17
+ 'max_price_required',
18
+ 'budget_required',
19
+ 'budget_exceeded',
20
+ 'base_rpc_required',
21
+ 'transport_required',
22
+ 'near_wallet_required',
23
+ 'base_wallet_required',
24
+ 'base_unavailable',
25
+ 'route_unavailable',
26
+ 'file_required',
27
+ 'offer_required',
28
+ 'purchase_required',
29
+ 'origin_required',
30
+ 'origin_asset_required',
31
+ 'origin_not_allowed',
32
+ 'resource_not_allowed',
33
+ 'path_not_allowed',
34
+ 'output_exists',
35
+ 'unknown_file',
36
+ 'already_registered',
37
+ 'taken_down',
38
+ 'sales_stopped',
39
+ 'unknown_moderator',
40
+ 'storage_required',
41
+ 'funding_refused',
42
+ 'file_storage_low',
43
+ 'protocol_fee_above_max',
44
+ 'price_mismatch',
45
+ 'price_above_max',
46
+ 'recipient_mismatch',
47
+ 'file_mismatch',
48
+ 'network_mismatch',
49
+ 'token_mismatch',
50
+ 'method_mismatch',
51
+ 'untrusted_contract',
52
+ 'file_invalid',
53
+ 'bad_requirements',
54
+ 'insufficient_balance',
55
+ 'smart_wallet_unsupported',
56
+ 'bad_signature',
57
+ 'payment_rejected',
58
+ 'purchase_open',
59
+ 'payment_id_conflict',
60
+ 'payment_expired',
61
+ 'payment_not_found',
62
+ 'payment_used',
63
+ 'quote_refused',
64
+ 'quote_expired',
65
+ 'settlement_pending',
66
+ 'transaction_uncertain',
67
+ 'not_sponsored',
68
+ 'not_buyer',
69
+ 'bad_magic',
70
+ 'unsupported_version',
71
+ 'bad_chunk_size',
72
+ 'header_too_large',
73
+ 'bad_header',
74
+ 'bad_stanza',
75
+ 'file_id_mismatch',
76
+ 'cipher_hash_mismatch',
77
+ 'seller_signature_invalid',
78
+ 'bad_body_length',
79
+ 'chunk_hash_mismatch',
80
+ 'no_usable_stanza',
81
+ 'key_unwrap_failed',
82
+ 'header_mac_invalid',
83
+ 'chunk_invalid',
84
+ 'meta_invalid',
85
+ 'preview_invalid',
86
+ 'ckd_failed',
87
+ 'ckd_invalid',
88
+ 'rejected',
89
+ 'wrong_chain',
90
+ 'wrong_identity',
91
+ 'invalid_signature',
92
+ 'missing_method',
93
+ 'invalid_response',
94
+ 'wallet_error',
95
+ 'store_conflict',
96
+ 'lease_busy',
97
+ 'source_changed',
98
+ 'sell_incomplete',
99
+ 'recovery_not_final',
100
+ 'transport',
101
+ 'refused',
102
+ 'bad_request',
103
+ 'bad_deadline',
104
+ 'limited',
105
+ 'duplicate',
106
+ 'in_flight',
107
+ 'unavailable',
108
+ 'disabled',
109
+ 'rate_limited',
110
+ 'budget',
111
+ 'busy',
112
+ 'not_found',
113
+ 'internal',
114
+ 'relayer_unavailable',
115
+ 'relayer_rate_limited',
116
+ 'base_rpc_rate_limited',
117
+ 'near_rpc_rate_limited',
118
+ 'host_payment_failed',
119
+ 'facilitator_busy',
120
+ 'bad_response',
121
+ 'not_authorized',
122
+ 'cancelled',
123
+ 'too_large',
124
+ 'download_limited',
125
+ 'download_in_progress',
126
+ 'file_expired',
127
+ 'upload_expired',
128
+ 'upload_conflict',
129
+ 'upload_incomplete',
130
+ 'host_capacity',
131
+ 'operation_failed',
132
+ ];
133
+ const messages = {
134
+ route_unavailable: 'This file does not support the selected payment route.',
135
+ host_payment_failed: 'Payment submission failed. Keep the saved purchase and check final status before retrying.',
136
+ bad_request: 'The request is invalid. Check its fields before retrying.',
137
+ bad_deadline: 'The authorization deadline is invalid or expired.',
138
+ invalid_arguments: 'Invalid arguments. Run annon --help.',
139
+ invalid_record: 'Invalid saved record. Export necessary test evidence and clear development state.',
140
+ transport: 'The service could not be reached. Keep saved state and retry later.',
141
+ recovery_not_final: 'The recovery grant is not final. Resume the saved recovery later.',
142
+ invalid_signature: 'The wallet did not authorize the exact requested message.',
143
+ operation_failed: 'Operation failed. Check configuration, funding and final purchase status before retrying. Saved encrypted records are retained.',
144
+ transaction_uncertain: 'Transaction submission is uncertain. Check the saved purchase and transaction hash before retrying.',
145
+ quote_refused: 'The 1Click quote was refused. Review the source asset and amount before retrying.',
146
+ base_rpc_rate_limited: 'The Base RPC is rate limiting requests. Configure a Base RPC endpoint with an API key (baseRpc).',
147
+ near_rpc_rate_limited: 'Configure a NEAR RPC endpoint with an API key (nearRpc).',
148
+ budget_exceeded: 'The persisted spending budget is exhausted.',
149
+ download_limited: 'Download limit reached. Wait before downloading again.',
150
+ download_in_progress: 'Another download is active. Wait before retrying.',
151
+ rate_limited: 'The host is busy. Wait before retrying.',
152
+ unavailable: 'The service is temporarily unavailable. Wait before retrying.',
153
+ transport_required: 'Configure a trusted relayer before a Base purchase.',
154
+ relayer_unavailable: 'Base sponsorship checks are unavailable. Retry before paying.',
155
+ not_sponsored: 'This listing does not qualify for Base sponsorship. Do not pay through this route.',
156
+ wrong_identity: 'The wallet does not control the required identity.',
157
+ settlement_pending: 'The purchase is still settling. Wait before retrying the saved purchase.',
158
+ protocol_fee_above_max: 'The advertised protocol fee exceeds maxProtocolFee. Review the fee in human configuration.',
159
+ funding_refused: 'File funding was refused. Correct the cause before retrying.',
160
+ file_storage_low: 'This file needs more purchase storage funding before a NEAR or 1Click payment.',
161
+ source_changed: 'The source changed between passes. Resume sell with the original plaintext and saved fileId.',
162
+ quote_expired: 'The 1Click quote expired. Run buy again.',
163
+ storage_required: 'Prepay storage with storageDeposit before register or reopen, then resume the saved operation.',
164
+ unknown_file: 'The configured contract has no such file. Check the file ID and deployment.',
165
+ taken_down: 'The moderator has taken down this file; key release is blocked.',
166
+ sales_stopped: 'The seller has stopped new sales. Use a saved purchase to open an earlier purchase.',
167
+ unknown_moderator: "Review this file's moderator and explicitly accept it with the moderator option before buying.",
168
+ price_above_max: 'The registered price exceeds maxPrice. Review the current terms before buying.',
169
+ untrusted_contract: 'The offer names a different contract. Review that deployment and configure it explicitly.',
170
+ network_mismatch: 'The deployment network or USDC asset differs from the configured network. Check the configuration.',
171
+ store_conflict: 'Another process updated this purchase. Keep the encrypted state and check status before retrying.',
172
+ file_invalid: 'The file failed SDK verification. Obtain the registered file from its host.',
173
+ file_mismatch: 'The file or offer differs from its registered commitment. Obtain the correct file or offer.',
174
+ bad_requirements: 'The host offer failed SDK validation. Obtain an updated Annon offer.',
175
+ not_authorized: 'The host has not accepted this final grant. Check final purchase status and the resource URL.',
176
+ };
177
+ export function isAnnonErrorCode(code) {
178
+ return typeof code === 'string' && annonErrorCodes.includes(code);
179
+ }
180
+ export function isTransient(error) {
181
+ const code = error && typeof error === 'object' && 'code' in error ? error.code : undefined;
182
+ return (code === 'transport' || code === 'base_rpc_rate_limited' || code === 'near_rpc_rate_limited');
183
+ }
184
+ export class AnnonError extends Error {
185
+ code;
186
+ constructor(code, message = messages[code] ?? `${code.replaceAll('_', ' ')}.`, options) {
187
+ super(message, options);
188
+ this.code = code;
189
+ this.name = 'AnnonError';
190
+ }
191
+ }
192
+ const waiting = new Set([
193
+ 'budget',
194
+ 'settlement_pending',
195
+ 'transaction_uncertain',
196
+ 'transport',
197
+ 'base_rpc_rate_limited',
198
+ 'near_rpc_rate_limited',
199
+ 'relayer_unavailable',
200
+ 'relayer_rate_limited',
201
+ 'download_limited',
202
+ 'download_in_progress',
203
+ 'rate_limited',
204
+ 'unavailable',
205
+ 'in_flight',
206
+ 'busy',
207
+ 'facilitator_busy',
208
+ 'lease_busy',
209
+ 'recovery_not_final',
210
+ 'host_capacity',
211
+ 'limited',
212
+ ]);
213
+ const approval = new Set([
214
+ 'agent_policy',
215
+ 'human_only',
216
+ 'confirmation_required',
217
+ 'sale_not_approved',
218
+ 'trust_required',
219
+ ]);
220
+ const input = new Set([
221
+ 'invalid_arguments',
222
+ 'invalid_config',
223
+ 'invalid_record',
224
+ 'config_conflict',
225
+ 'agent_policy',
226
+ 'human_only',
227
+ 'confirmation_required',
228
+ 'sale_not_approved',
229
+ 'trust_required',
230
+ 'signer_required',
231
+ 'signer_init_only',
232
+ 'credentials_required',
233
+ 'backup_secret_required',
234
+ 'work_dir_required',
235
+ 'max_price_required',
236
+ 'budget_required',
237
+ 'base_rpc_required',
238
+ 'transport_required',
239
+ 'near_wallet_required',
240
+ 'base_wallet_required',
241
+ 'base_unavailable',
242
+ 'route_unavailable',
243
+ 'file_required',
244
+ 'offer_required',
245
+ 'purchase_required',
246
+ 'origin_required',
247
+ 'origin_asset_required',
248
+ 'origin_not_allowed',
249
+ 'resource_not_allowed',
250
+ 'path_not_allowed',
251
+ 'output_exists',
252
+ 'network_mismatch',
253
+ 'bad_request',
254
+ 'bad_deadline',
255
+ ]);
256
+ export function toPublicError(error) {
257
+ const e = error && typeof error === 'object' ? error : {};
258
+ if (!isAnnonErrorCode(e.code))
259
+ return {
260
+ code: 'operation_failed',
261
+ message: messages.operation_failed ?? 'Operation failed.',
262
+ exitCode: 1,
263
+ };
264
+ const code = e.code;
265
+ const adapter = error instanceof AnnonError && error.name === 'AdapterError'
266
+ ? error
267
+ : undefined;
268
+ const id = (v) => typeof v === 'string' && /^0x[0-9a-f]{64}$/.test(v);
269
+ const seconds = typeof e.retryAfterSeconds === 'number' && e.retryAfterSeconds >= 0
270
+ ? Math.ceil(e.retryAfterSeconds)
271
+ : NaN;
272
+ const retryAfterSeconds = Number.isSafeInteger(seconds)
273
+ ? seconds
274
+ : code === 'settlement_pending'
275
+ ? 30
276
+ : undefined;
277
+ return {
278
+ code,
279
+ message: (code === 'route_unavailable' ? messages.route_unavailable : adapter?.message) ??
280
+ (messages[code] ?? `${code.replaceAll('_', ' ')}.`) +
281
+ (error instanceof AnnonError && error.name === 'SellError' && code !== 'source_changed'
282
+ ? ' Resume sell with the original plaintext and saved fileId.'
283
+ : ''),
284
+ exitCode: (code === 'route_unavailable' ? 2 : adapter?.exitCode) ??
285
+ (waiting.has(code) ? 4 : approval.has(code) ? 3 : input.has(code) ? 2 : 1),
286
+ ...(id(e.fileId) ? { fileId: e.fileId } : {}),
287
+ ...(id(e.purchaseId) ? { purchaseId: e.purchaseId } : {}),
288
+ ...(typeof e.txHash === 'string' ? { txHash: e.txHash } : {}),
289
+ ...(typeof e.minimumAmountUsdc === 'string' &&
290
+ /^(0|[1-9][0-9]*)(\.[0-9]+)?$/.test(e.minimumAmountUsdc)
291
+ ? { minimumAmountUsdc: e.minimumAmountUsdc }
292
+ : {}),
293
+ ...(retryAfterSeconds !== undefined ? { retryAfterSeconds } : {}),
294
+ };
295
+ }
296
+ export function present(value, code = 'invalid_record') {
297
+ if (value === null || value === undefined)
298
+ throw new AnnonError(code);
299
+ return value;
300
+ }
@@ -0,0 +1,25 @@
1
+ export { Annon, type AnnonOptions, type Bought, type BuyOptions, type BuyRoute, SellError, type SellOptions, } from './api/annon.js';
2
+ export type { HostedCheckpoint, Shared, ShareHosting, ShareOptions, ShareQuote, ShareStep, } from './api/sharing.js';
3
+ export { PurchaseLeaseBusy } from './browser/purchases.js';
4
+ export { BrowserWalletError, type BrowserWalletErrorCode } from './browser/wallets.js';
5
+ export { DownloadError, type DownloadErrorCode } from './download/download.js';
6
+ export { type UploadAuth, type UploadAuthorization, type UploadBaseSplit, type UploadBaseSplitResult, UploadClient, type UploadIntent, type UploadManifest, type UploadMetadata, type UploadPublished, type UploadStatus, uploadText, } from './download/upload.js';
7
+ export { Pay2Error, type Pay2ErrorCode } from './envelope/pay2.js';
8
+ export { blobSource, type ReplayableSource, type Spool } from './envelope/replay.js';
9
+ export { SourceChangedError } from './envelope/stream.js';
10
+ export { AnnonError, type AnnonErrorCode, isTransient, type PublicError, toPublicError, } from './errors.js';
11
+ export { CkdError, type CkdErrorCode } from './keys/near-ckd.js';
12
+ export { HTTP_RETRY_MAX_WAIT_SECONDS, MAX_PAY2_BYTES, MAX_PLAINTEXT_BYTES } from './limits.js';
13
+ export { type FileStorageBalance, fileStorageBalance, NearError, type NearErrorCode, NearRpcRateLimited, } from './near/rpc.js';
14
+ export { type FileFundingArgs, fileFundingText } from './near/texts.js';
15
+ export { type Deposit, OneClick, type OneClickQuote, OneClickQuoteExpired, OneClickRefused, type Origin, originFromToken, type PollCheckpoint, type PollOptions, type QuotePreview, type SwapStatus, type Token, validateRefundAddress, } from './oneclick/oneclick.js';
16
+ export { type EncryptedRecord, encryptedPurchaseStore, encryptedRecoveryStore, exportPurchase, exportRecovery, exportSell, exportSellerKey, importPurchase, importRecovery, importSell, importSellerKey, newBackupSecret, type RecoveryRecord, type SellerKeyRecord, type SellRecord, } from './pay/backup.js';
17
+ export { BaseRpcRateLimited, PayError, type PayErrorCode } from './pay/base.js';
18
+ export type { PurchaseRecord } from './pay/purchase.js';
19
+ export { BASE_ELIGIBILITY_MAX_AGE_SECONDS, type BaseSponsorship, type BaseSponsorshipOptions, checkBaseSponsorship, validBaseSponsorship, } from './relay/capabilities.js';
20
+ export { DEFAULT_MAX_PROTOCOL_FEE, type ProtocolFee } from './relay/fees.js';
21
+ export { type Authorization, type Identity, identityText, parseIdentity, verifyAuthorization, } from './settle-near/identity.js';
22
+ export { type BaseTerms, type NearTerms, type SettlementAssets, type Terms, termsHash, } from './settle-near/terms.js';
23
+ export { type CatalogEntry, type CatalogQuery, type ConfiguredShop, canonicalManifestUrl, catalog, type DiscoveryConfig, type DiscoveryPage, type DiscoveryQuery, listShops, type Shop, type ShopFailure, type ShopManifest, type ShopProfile, type ShopRules, } from './shops/discovery.js';
24
+ export { TransactionUncertain } from './wallet/uncertain.js';
25
+ export { type EvmWallet, evmWallet, FileFundingRefused, fundFileStorage, type IdentityWallet, type NearWallet, nearKeyPairWallet, nearSelectorWallet, solanaWallet, storageDeposit, } from './wallet/wallet.js';
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ export { Annon, SellError, } from './api/annon.js';
2
+ export { PurchaseLeaseBusy } from './browser/purchases.js';
3
+ export { BrowserWalletError } from './browser/wallets.js';
4
+ export { DownloadError } from './download/download.js';
5
+ export { UploadClient, uploadText, } from './download/upload.js';
6
+ export { Pay2Error } from './envelope/pay2.js';
7
+ export { blobSource } from './envelope/replay.js';
8
+ export { SourceChangedError } from './envelope/stream.js';
9
+ export { AnnonError, isTransient, toPublicError, } from './errors.js';
10
+ export { CkdError } from './keys/near-ckd.js';
11
+ export { HTTP_RETRY_MAX_WAIT_SECONDS, MAX_PAY2_BYTES, MAX_PLAINTEXT_BYTES } from './limits.js';
12
+ export { fileStorageBalance, NearError, NearRpcRateLimited, } from './near/rpc.js';
13
+ export { fileFundingText } from './near/texts.js';
14
+ export { OneClick, OneClickQuoteExpired, OneClickRefused, originFromToken, validateRefundAddress, } from './oneclick/oneclick.js';
15
+ export { encryptedPurchaseStore, encryptedRecoveryStore, exportPurchase, exportRecovery, exportSell, exportSellerKey, importPurchase, importRecovery, importSell, importSellerKey, newBackupSecret, } from './pay/backup.js';
16
+ export { BaseRpcRateLimited, PayError } from './pay/base.js';
17
+ export { BASE_ELIGIBILITY_MAX_AGE_SECONDS, checkBaseSponsorship, validBaseSponsorship, } from './relay/capabilities.js';
18
+ export { DEFAULT_MAX_PROTOCOL_FEE } from './relay/fees.js';
19
+ export { identityText, parseIdentity, verifyAuthorization, } from './settle-near/identity.js';
20
+ export { termsHash, } from './settle-near/terms.js';
21
+ export { canonicalManifestUrl, catalog, listShops, } from './shops/discovery.js';
22
+ export { TransactionUncertain } from './wallet/uncertain.js';
23
+ export { evmWallet, FileFundingRefused, fundFileStorage, nearKeyPairWallet, nearSelectorWallet, solanaWallet, storageDeposit, } from './wallet/wallet.js';
@@ -0,0 +1,47 @@
1
+ import { AnnonError } from '../errors.js';
2
+ declare const G1: import("@noble/curves/abstract/weierstrass.js").WeierstrassPointCons<bigint>;
3
+ declare const G2: import("@noble/curves/abstract/weierstrass.js").WeierstrassPointCons<import("@noble/curves/abstract/tower.js").Fp2>;
4
+ export type CkdErrorCode =
5
+ /** MPC didn't answer; the purchase stands and `reopen` gets the key. */
6
+ 'ckd_failed'
7
+ /** An answer that isn't a valid key for this file and this one-time key. */
8
+ | 'ckd_invalid';
9
+ export declare class CkdError extends AnnonError {
10
+ readonly code: CkdErrorCode;
11
+ constructor(code: CkdErrorCode, message?: string);
12
+ }
13
+ interface OneTimeKey {
14
+ /** The scalar `a`, 32 bytes big-endian. Persist only in an encrypted purchase or recovery record. */
15
+ secret: Uint8Array;
16
+ /** `A = a·G1` as the contract takes it: `bls12381g1:<base58 of 48 bytes>`. */
17
+ publicKey: string;
18
+ /** The same 48 bytes, for the payment nonce. */
19
+ publicKeyBytes: Uint8Array;
20
+ }
21
+ /** A fresh one-time key pair. */
22
+ export declare function oneTimeKey(): OneTimeKey;
23
+ /** @internal The key pair for a known scalar (tests, recovery from a stored job). */
24
+ export declare function keyFromSecret(secret: Uint8Array): OneTimeKey;
25
+ /** NEAR's `derive_app_id`: sha3-256 of `"near-mpc v0.1.0 app_id derivation:" + account + "," + path`. */
26
+ export declare const appId: (account: string, path: string) => Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
27
+ /** The app id of a file: the contract asks CKD for `file/<fileId, lowercase hex>`. */
28
+ export declare const fileAppId: (contractId: string, fileId: Uint8Array) => Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
29
+ interface OpenAnswerOptions {
30
+ /** The one-time secret whose public key went with the request. */
31
+ secret: Uint8Array;
32
+ /** `fileAppId(contractId, fileId)` for an Annon file. */
33
+ appId: Uint8Array;
34
+ /** `bls12381g2:…` read from the trusted contract's MPC account and CKD domain. */
35
+ mpcKey: string;
36
+ }
37
+ /**
38
+ * Turns the contract's return value into the file's CKD secret: the 48-byte G1 point the envelope
39
+ * takes as `ckdSecret`. Decrypts `big_c − a·big_y`, then checks it is MPC's BLS signature on this
40
+ * app id, `e(H(pk ‖ appId), pk) = e(sig, G2)`, so a wrong or forged answer never reaches the file.
41
+ */
42
+ export declare function openAnswer(answer: unknown, opts: OpenAnswerOptions): Uint8Array;
43
+ /** @internal The scheme on decoded points, as NEAR's vectors state it. */
44
+ export declare function decrypt(a: bigint, Y: InstanceType<typeof G1>, C: InstanceType<typeof G1>, pk: InstanceType<typeof G2>, id: Uint8Array): import("@noble/curves/abstract/weierstrass.js").WeierstrassPoint<bigint>;
45
+ /** @internal `H(pk, app_id)`: RFC 9380 hash to G1 over `pk_compressed (96 B) ‖ app_id`. */
46
+ export declare const hashPoint: (pk: InstanceType<typeof G2>, id: Uint8Array) => import("@noble/curves/abstract/weierstrass.js").WeierstrassPoint<bigint>;
47
+ export {};
@@ -0,0 +1,96 @@
1
+ /**
2
+ * NEAR CKD on the client (`specs/pay2.md`, section 5.1): the one-time key a seller or buyer sends
3
+ * with `register`, `unlock` or `reopen`, and the checks that the secret NEAR MPC sends back is the
4
+ * right one before the envelope uses it. Same scheme as NEAR's own test vectors
5
+ * (`specs/vectors/ckd-near-mpc.json`).
6
+ */
7
+ import { bls12_381 as bls } from '@noble/curves/bls12-381.js';
8
+ import { sha3_256 } from '@noble/hashes/sha3.js';
9
+ import { base58 } from '@scure/base';
10
+ import { AnnonError } from '../errors.js';
11
+ const G1 = bls.G1.Point;
12
+ const G2 = bls.G2.Point;
13
+ const Fr = bls.fields.Fr;
14
+ const DST = 'NEAR BLS12381G1_XMD:SHA-256_SSWU_RO_';
15
+ export class CkdError extends AnnonError {
16
+ code;
17
+ constructor(code, message = code) {
18
+ super(code, message);
19
+ this.code = code;
20
+ this.name = 'CkdError';
21
+ }
22
+ }
23
+ const fail = (code, message) => {
24
+ throw new CkdError(code, message);
25
+ };
26
+ /** A fresh one-time key pair. */
27
+ export function oneTimeKey() {
28
+ const a = toScalar(bls.utils.randomSecretKey()) % Fr.ORDER;
29
+ return keyFromSecret(fromScalar(a === 0n ? 1n : a));
30
+ }
31
+ /** @internal The key pair for a known scalar (tests, recovery from a stored job). */
32
+ export function keyFromSecret(secret) {
33
+ const A = G1.BASE.multiply(scalar(secret)).toBytes(true);
34
+ return { secret, publicKey: `bls12381g1:${base58.encode(A)}`, publicKeyBytes: A };
35
+ }
36
+ /** NEAR's `derive_app_id`: sha3-256 of `"near-mpc v0.1.0 app_id derivation:" + account + "," + path`. */
37
+ export const appId = (account, path) => sha3_256(new TextEncoder().encode(`near-mpc v0.1.0 app_id derivation:${account},${path}`));
38
+ /** The app id of a file: the contract asks CKD for `file/<fileId, lowercase hex>`. */
39
+ export const fileAppId = (contractId, fileId) => appId(contractId, `file/${Array.from(fileId, (x) => x.toString(16).padStart(2, '0')).join('')}`);
40
+ /**
41
+ * Turns the contract's return value into the file's CKD secret: the 48-byte G1 point the envelope
42
+ * takes as `ckdSecret`. Decrypts `big_c − a·big_y`, then checks it is MPC's BLS signature on this
43
+ * app id, `e(H(pk ‖ appId), pk) = e(sig, G2)`, so a wrong or forged answer never reaches the file.
44
+ */
45
+ export function openAnswer(answer, opts) {
46
+ const a = answer;
47
+ if (a && typeof a.error === 'string')
48
+ fail('ckd_failed', a.error);
49
+ const Y = point(G1, a?.big_y, 'bls12381g1:', 48);
50
+ const C = point(G1, a?.big_c, 'bls12381g1:', 48);
51
+ const pk = point(G2, opts.mpcKey, 'bls12381g2:', 96);
52
+ return decrypt(scalar(opts.secret), Y, C, pk, opts.appId).toBytes(true);
53
+ }
54
+ /** @internal The scheme on decoded points, as NEAR's vectors state it. */
55
+ export function decrypt(a, Y, C, pk, id) {
56
+ const sig = C.subtract(Y.multiply(a));
57
+ const H = hashPoint(pk, id);
58
+ let ok = false;
59
+ try {
60
+ // noble refuses to pair the identity point; that answer is invalid all the same.
61
+ ok = !sig.is0() && bls.fields.Fp12.eql(bls.pairing(H, pk), bls.pairing(sig, G2.BASE));
62
+ }
63
+ catch { }
64
+ if (!ok)
65
+ fail('ckd_invalid', 'the answer is not the key for this file and this one-time key');
66
+ return sig;
67
+ }
68
+ /** @internal `H(pk, app_id)`: RFC 9380 hash to G1 over `pk_compressed (96 B) ‖ app_id`. */
69
+ export const hashPoint = (pk, id) => bls.shortSignatures.hash(new Uint8Array([...pk.toBytes(true), ...id]), DST);
70
+ // Scalars are 32 bytes big-endian, as in NEAR's vectors.
71
+ const toScalar = (b) => BigInt(`0x${Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('') || '0'}`);
72
+ const fromScalar = (a) => Uint8Array.from(a.toString(16).padStart(64, '0').match(/../g) ?? [], (x) => Number.parseInt(x, 16));
73
+ function scalar(secret) {
74
+ if (secret.length !== 32)
75
+ throw new TypeError('the one-time secret is 32 bytes');
76
+ const a = toScalar(secret);
77
+ if (a === 0n || a >= Fr.ORDER)
78
+ throw new TypeError('the one-time secret is not a valid scalar');
79
+ return a;
80
+ }
81
+ /** Decodes `prefix` + base58 into a point of the prime subgroup. */
82
+ function point(group, s, prefix, len) {
83
+ if (typeof s !== 'string' || !s.startsWith(prefix))
84
+ return fail('ckd_invalid', 'bad point');
85
+ try {
86
+ const bytes = base58.decode(s.slice(prefix.length));
87
+ if (bytes.length !== len)
88
+ throw new Error('length');
89
+ // fromBytes rejects points off the curve or outside the prime subgroup (tested); a zero or
90
+ // otherwise wrong point fails the pairing check.
91
+ return group.fromBytes(bytes);
92
+ }
93
+ catch {
94
+ return fail('ckd_invalid', 'bad point');
95
+ }
96
+ }
@@ -0,0 +1,4 @@
1
+ /** Decimal byte limits shared by every client transport. */
2
+ export declare const MAX_PLAINTEXT_BYTES = 50000000;
3
+ export declare const MAX_PAY2_BYTES = 50086016;
4
+ export declare const HTTP_RETRY_MAX_WAIT_SECONDS = 60;
package/dist/limits.js ADDED
@@ -0,0 +1,4 @@
1
+ /** Decimal byte limits shared by every client transport. */
2
+ export const MAX_PLAINTEXT_BYTES = 50_000_000;
3
+ export const MAX_PAY2_BYTES = 50_086_016;
4
+ export const HTTP_RETRY_MAX_WAIT_SECONDS = 60;
@@ -0,0 +1,22 @@
1
+ export interface NearMessage {
2
+ message: string;
3
+ recipient: string;
4
+ nonce: Uint8Array;
5
+ callbackUrl?: string;
6
+ state?: string;
7
+ }
8
+ export interface NearSignedMessage {
9
+ accountId: string;
10
+ publicKey: string;
11
+ signature: string;
12
+ }
13
+ export interface RecoveryProofContext {
14
+ contractId: string;
15
+ nearRpc: string;
16
+ callbackUrl?: string;
17
+ }
18
+ /** u32 tag (2^31+413), Borsh message, fixed nonce, recipient, Option<string> callbackUrl. */
19
+ export declare function nep413Hash(p: NearMessage): Uint8Array;
20
+ export declare function proveNearControl(accountId: string, text: string, context: RecoveryProofContext, signMessage: (p: NearMessage) => Promise<NearSignedMessage | undefined>): Promise<void>;
21
+ /** Verify exact NEP-413 payload and finalized full-access membership. */
22
+ export declare function verifyNearMessage(accountId: string, payload: NearMessage, result: NearSignedMessage | undefined, nearRpc: string): Promise<void>;
@@ -0,0 +1,39 @@
1
+ /** NEP-413: https://github.com/near/NEPs/blob/master/neps/nep-0413.md */
2
+ import { ed25519 } from '@noble/curves/ed25519.js';
3
+ import { sha256 } from '@noble/hashes/sha2.js';
4
+ import { base58, base64 } from '@scure/base';
5
+ import { AnnonError } from '../errors.js';
6
+ import { account, concat, le, str } from '../settle-near/codec.js';
7
+ import { isFullAccessKey } from './rpc.js';
8
+ /** u32 tag (2^31+413), Borsh message, fixed nonce, recipient, Option<string> callbackUrl. */
9
+ export function nep413Hash(p) {
10
+ if (p.nonce.length !== 32)
11
+ throw new TypeError('NEP-413 nonce must be 32 bytes');
12
+ return sha256(concat(le(2147484061, 4), str(p.message), p.nonce, str(p.recipient), p.callbackUrl === undefined ? le(0, 1) : concat(le(1, 1), str(p.callbackUrl))));
13
+ }
14
+ export async function proveNearControl(accountId, text, context, signMessage) {
15
+ account(accountId);
16
+ account(context.contractId);
17
+ const payload = {
18
+ ...(context.callbackUrl === undefined ? {} : { callbackUrl: context.callbackUrl }),
19
+ message: text,
20
+ recipient: context.contractId,
21
+ nonce: crypto.getRandomValues(new Uint8Array(32)),
22
+ };
23
+ const result = await signMessage({ ...payload, nonce: payload.nonce.slice() });
24
+ await verifyNearMessage(accountId, payload, result, context.nearRpc);
25
+ }
26
+ /** Verify exact NEP-413 payload and finalized full-access membership. */
27
+ export async function verifyNearMessage(accountId, payload, result, nearRpc) {
28
+ const hash = nep413Hash(payload);
29
+ if (!result || result.accountId !== accountId || !result.publicKey.startsWith('ed25519:'))
30
+ throw new AnnonError('invalid_signature', 'NEP-413 proof belongs to another account or key type');
31
+ const key = base58.decode(result.publicKey.slice(8));
32
+ const signature = base64.decode(result.signature);
33
+ if (key.length !== 32 ||
34
+ signature.length !== 64 ||
35
+ !ed25519.verify(signature, hash, key, { zip215: false }))
36
+ throw new AnnonError('invalid_signature', 'invalid NEP-413 recovery signature');
37
+ if (!(await isFullAccessKey(nearRpc, accountId, result.publicKey)))
38
+ throw new AnnonError('invalid_signature', 'NEP-413 recovery requires a full-access key');
39
+ }