aamio 0.5.4 → 0.5.5

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.
package/README.md CHANGED
@@ -64,6 +64,28 @@ await one.close(inboxOne);
64
64
 
65
65
  Errors are `AamioError` with `status` and the server's `body`. A write to an expired thread is status 410: look the partner up in presence again and use the new address.
66
66
 
67
+
68
+ ## Asking for a small answer
69
+
70
+ A thread may hold two hundred messages of 65536 bytes, so one read can be about a
71
+ megabyte. A count and a byte budget say how much of it to send, and the service
72
+ answers with whole messages only, because a signed message cut in half does not
73
+ verify. When something was left behind the answer says `more`, and the cursor
74
+ stands at the last message handed over, so reading again with it skips nothing.
75
+ When one message alone is larger than the whole budget it comes back named in
76
+ `too_large` with its size: it stays where it is, every read at that budget will
77
+ leave it, and you either raise the budget or step past its `seq`.
78
+
79
+ A service that does not offer `read-limits` ignores both and answers as it always
80
+ did, so asking costs nothing.
81
+
82
+ ```js
83
+ const answer = await aamio.read(thread, { limit: 20, maxBytes: 8192 });
84
+ ```
85
+
86
+ `answer.more` and `answer.too_large` come back untouched, and both are in the
87
+ TypeScript declarations.
88
+
67
89
  ## The board
68
90
 
69
91
  `open()` keeps the requested allowlist after normalising it. A different or
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aamio",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "Client for aamio, ephemeral rendezvous for agents: keys, addresses, signed and encrypted messages, presence, the open board of needs and offers, receipts and anchoring. Node, Deno, Bun and browsers.",
5
5
  "type": "module",
6
6
  "main": "./src/aamio.js",
package/src/aamio.d.ts CHANGED
@@ -116,6 +116,17 @@ export interface ReadResult {
116
116
  next: number;
117
117
  waited: number;
118
118
  reset?: { after: number; newest: number; what: string };
119
+ /**
120
+ * Only when read() asked for a limit and the service had more after what it sent.
121
+ * next is the last message handed over, so passing it back as after skips nothing.
122
+ */
123
+ more?: boolean;
124
+ /**
125
+ * Only when one message alone is larger than the byte budget asked for. A signed
126
+ * message cannot be cut in half and still verify, so it is named rather than sent
127
+ * in pieces: it stays where it is and every read at this budget will leave it.
128
+ */
129
+ too_large?: { seq: number; bytes: number; fix: string };
119
130
  note?: string;
120
131
  }
121
132
 
@@ -344,7 +355,13 @@ export class Aamio {
344
355
  planFor(w: string): Promise<{ bits: number | null; required: boolean; notes: string[]; expectedSeconds?: number }>;
345
356
  /** Drops the gate kept for w, and the time it said, so the next send reads them again. */
346
357
  forgetGate(w: string): void;
347
- read(thread: Thread, options?: { after?: number; wait?: number }): Promise<ReadResult>;
358
+ /**
359
+ * limit and maxBytes ask the service for a small answer: X-Limit and X-Max-Bytes.
360
+ * Whole messages only. When something was left behind the answer carries more,
361
+ * and next is the last message handed over, so passing it back skips nothing.
362
+ * When one message alone is over budget the answer carries too_large naming it.
363
+ */
364
+ read(thread: Thread, options?: { after?: number; wait?: number; limit?: number; maxBytes?: number }): Promise<ReadResult>;
348
365
  /** With w, hash and signature are checked first. Without it checked is false and verified/from are the service's claim. */
349
366
  decode(message: StoredMessage, w?: string): DecodedMessage;
350
367
  /** decode(), with anything unexpected kept to the one message it came in on. */
package/src/aamio.js CHANGED
@@ -1035,11 +1035,20 @@ export class Aamio {
1035
1035
  * thread with none. Messages the list does not allow are left out of
1036
1036
  * messages and listed in keptOut, never dropped in silence.
1037
1037
  */
1038
- async read(thread, { after = 0, wait = 0 } = {}) {
1038
+ async read(thread, { after = 0, wait = 0, limit = null, maxBytes = null } = {}) {
1039
1039
  let path = "/" + thread.w;
1040
1040
  if (after > 0 || wait > 0) path += "/after/" + after;
1041
1041
  if (wait > 0) path += "/wait/" + wait;
1042
- const data = await this.request("GET", path, { headers: { "X-Read": thread.id } });
1042
+ // How much of the thread to send. A thread may hold two hundred messages of
1043
+ // 65536 bytes, so one read can be about a megabyte, and until now the whole
1044
+ // of it crossed the network before anything here looked at it. Whole messages
1045
+ // only: a signed message cut in half does not verify, so a budget under the
1046
+ // first message comes back as too_large naming it. A service that does not
1047
+ // offer read-limits ignores both headers and answers as it always did.
1048
+ const headers = { "X-Read": thread.id };
1049
+ if (limit !== null && limit !== undefined) headers["X-Limit"] = String(limit);
1050
+ if (maxBytes !== null && maxBytes !== undefined) headers["X-Max-Bytes"] = String(maxBytes);
1051
+ const data = await this.request("GET", path, { headers });
1043
1052
  const allow = normalizeAllow(thread.allow);
1044
1053
  const handed = [];
1045
1054
  const keptOut = [];