hanzoai 8.5.621 → 8.5.640

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 (168) hide show
  1. package/README.md +64 -9
  2. package/dist/answer.js +20 -10
  3. package/dist/api/ai-api.d.ts +280 -14
  4. package/dist/api/ai-api.js +315 -29
  5. package/dist/api/auto-api.d.ts +64 -0
  6. package/dist/api/auto-api.js +77 -0
  7. package/dist/api/billing-api.d.ts +4 -4
  8. package/dist/api/billing-api.js +4 -4
  9. package/dist/api/git-api.d.ts +30 -0
  10. package/dist/api/git-api.js +59 -0
  11. package/dist/api/task-api.d.ts +55 -0
  12. package/dist/api/task-api.js +71 -0
  13. package/dist/client.d.ts +3 -2
  14. package/dist/client.js +4 -3
  15. package/dist/esm/answer.js +20 -10
  16. package/dist/esm/api/ai-api.d.ts +280 -14
  17. package/dist/esm/api/ai-api.js +315 -29
  18. package/dist/esm/api/auto-api.d.ts +64 -0
  19. package/dist/esm/api/auto-api.js +77 -0
  20. package/dist/esm/api/billing-api.d.ts +4 -4
  21. package/dist/esm/api/billing-api.js +4 -4
  22. package/dist/esm/api/git-api.d.ts +30 -0
  23. package/dist/esm/api/git-api.js +59 -0
  24. package/dist/esm/api/task-api.d.ts +55 -0
  25. package/dist/esm/api/task-api.js +71 -0
  26. package/dist/esm/client.d.ts +3 -2
  27. package/dist/esm/client.js +3 -2
  28. package/dist/esm/hanzo.d.ts +3 -0
  29. package/dist/esm/hanzo.js +6 -0
  30. package/dist/esm/models/agent-target-view.d.ts +6 -0
  31. package/dist/esm/models/ai-chat-in.d.ts +42 -0
  32. package/dist/esm/models/ai-chat.d.ts +37 -0
  33. package/dist/esm/models/ai-decide-in.d.ts +50 -0
  34. package/dist/esm/models/ai-decide-in.js +14 -0
  35. package/dist/esm/models/ai-decision-sides.d.ts +4 -5
  36. package/dist/esm/models/{ai-decision-sides-false.d.ts → ai-decision.d.ts} +15 -2
  37. package/dist/esm/models/ai-decision.js +14 -0
  38. package/dist/esm/models/ai-decisions-answer.d.ts +2 -3
  39. package/dist/esm/models/ai-decisions-choice.d.ts +4 -8
  40. package/dist/esm/models/ai-decisions-noul.d.ts +2 -3
  41. package/dist/esm/models/ai-decisions-request.d.ts +2 -3
  42. package/dist/esm/models/ai-decisions-score.d.ts +4 -5
  43. package/dist/esm/models/ai-model.d.ts +73 -0
  44. package/dist/esm/models/ai-model.js +14 -0
  45. package/dist/esm/models/{ai-decisions-choice-criteria-value.d.ts → ai-models.d.ts} +15 -2
  46. package/dist/esm/models/ai-models.js +14 -0
  47. package/dist/esm/models/ai-price.d.ts +48 -0
  48. package/dist/esm/models/ai-price.js +14 -0
  49. package/dist/esm/models/ai-receipt.d.ts +60 -0
  50. package/dist/esm/models/ai-receipt.js +14 -0
  51. package/dist/esm/models/ai-routing-reward-request.d.ts +54 -0
  52. package/dist/esm/models/ai-routing-reward-request.js +24 -0
  53. package/dist/esm/models/auto-automation-in.d.ts +6 -0
  54. package/dist/esm/models/auto-automation-patch.d.ts +6 -0
  55. package/dist/esm/models/auto-automation-run.d.ts +14 -1
  56. package/dist/esm/models/auto-automation.d.ts +6 -0
  57. package/dist/esm/models/auto-post-result.d.ts +36 -0
  58. package/dist/esm/models/auto-post-result.js +14 -0
  59. package/dist/esm/models/auto-review-in.d.ts +36 -0
  60. package/dist/esm/models/auto-review-in.js +14 -0
  61. package/dist/esm/models/git-workspace-view.d.ts +36 -0
  62. package/dist/esm/models/git-workspace-view.js +14 -0
  63. package/dist/esm/models/iam-user.d.ts +1 -1
  64. package/dist/esm/models/index.d.ts +14 -2
  65. package/dist/esm/models/index.js +14 -2
  66. package/dist/esm/models/provider-github-import-out.d.ts +6 -0
  67. package/dist/esm/models/provider-github-repo-item.d.ts +6 -0
  68. package/dist/esm/models/task-comment-list.d.ts +31 -0
  69. package/dist/esm/models/task-comment-list.js +14 -0
  70. package/dist/esm/models/task-comment.d.ts +42 -0
  71. package/dist/esm/models/task-comment.js +14 -0
  72. package/dist/esm/transport.d.ts +4 -0
  73. package/dist/esm/transport.js +188 -0
  74. package/dist/esm/usage.d.ts +98 -0
  75. package/dist/esm/usage.js +161 -0
  76. package/dist/hanzo.d.ts +3 -0
  77. package/dist/hanzo.js +16 -1
  78. package/dist/models/agent-target-view.d.ts +6 -0
  79. package/dist/models/ai-chat-in.d.ts +42 -0
  80. package/dist/models/ai-chat.d.ts +37 -0
  81. package/dist/models/ai-decide-in.d.ts +50 -0
  82. package/dist/models/ai-decide-in.js +15 -0
  83. package/dist/models/ai-decision-sides.d.ts +4 -5
  84. package/dist/models/{ai-decision-sides-false.d.ts → ai-decision.d.ts} +15 -2
  85. package/dist/models/ai-decision.js +15 -0
  86. package/dist/models/ai-decisions-answer.d.ts +2 -3
  87. package/dist/models/ai-decisions-choice.d.ts +4 -8
  88. package/dist/models/ai-decisions-noul.d.ts +2 -3
  89. package/dist/models/ai-decisions-request.d.ts +2 -3
  90. package/dist/models/ai-decisions-score.d.ts +4 -5
  91. package/dist/models/ai-model.d.ts +73 -0
  92. package/dist/models/ai-model.js +15 -0
  93. package/dist/models/{ai-decisions-choice-criteria-value.d.ts → ai-models.d.ts} +15 -2
  94. package/dist/models/ai-models.js +15 -0
  95. package/dist/models/ai-price.d.ts +48 -0
  96. package/dist/models/ai-price.js +15 -0
  97. package/dist/models/ai-receipt.d.ts +60 -0
  98. package/dist/models/ai-receipt.js +15 -0
  99. package/dist/models/ai-routing-reward-request.d.ts +54 -0
  100. package/dist/models/ai-routing-reward-request.js +27 -0
  101. package/dist/models/auto-automation-in.d.ts +6 -0
  102. package/dist/models/auto-automation-patch.d.ts +6 -0
  103. package/dist/models/auto-automation-run.d.ts +14 -1
  104. package/dist/models/auto-automation.d.ts +6 -0
  105. package/dist/models/auto-post-result.d.ts +36 -0
  106. package/dist/models/auto-post-result.js +15 -0
  107. package/dist/models/auto-review-in.d.ts +36 -0
  108. package/dist/models/auto-review-in.js +15 -0
  109. package/dist/models/git-workspace-view.d.ts +36 -0
  110. package/dist/models/git-workspace-view.js +15 -0
  111. package/dist/models/iam-user.d.ts +1 -1
  112. package/dist/models/index.d.ts +14 -2
  113. package/dist/models/index.js +14 -2
  114. package/dist/models/provider-github-import-out.d.ts +6 -0
  115. package/dist/models/provider-github-repo-item.d.ts +6 -0
  116. package/dist/models/task-comment-list.d.ts +31 -0
  117. package/dist/models/task-comment-list.js +15 -0
  118. package/dist/models/task-comment.d.ts +42 -0
  119. package/dist/models/task-comment.js +15 -0
  120. package/dist/transport.d.ts +4 -0
  121. package/dist/transport.js +195 -0
  122. package/dist/usage.d.ts +98 -0
  123. package/dist/usage.js +174 -0
  124. package/package.json +1 -1
  125. package/src/answer.ts +23 -10
  126. package/src/api/ai-api.ts +503 -29
  127. package/src/api/auto-api.ts +117 -0
  128. package/src/api/billing-api.ts +4 -4
  129. package/src/api/git-api.ts +68 -0
  130. package/src/api/task-api.ts +101 -0
  131. package/src/client.ts +3 -2
  132. package/src/hanzo.ts +18 -0
  133. package/src/models/agent-target-view.ts +6 -0
  134. package/src/models/ai-chat-in.ts +48 -0
  135. package/src/models/ai-chat.ts +45 -0
  136. package/src/models/ai-decide-in.ts +54 -0
  137. package/src/models/ai-decision-sides.ts +4 -7
  138. package/src/models/{ai-decision-sides-false.ts → ai-decision.ts} +17 -2
  139. package/src/models/ai-decisions-answer.ts +2 -5
  140. package/src/models/ai-decisions-choice.ts +4 -10
  141. package/src/models/ai-decisions-noul.ts +2 -5
  142. package/src/models/ai-decisions-question.ts +0 -3
  143. package/src/models/ai-decisions-request.ts +2 -5
  144. package/src/models/ai-decisions-score.ts +4 -7
  145. package/src/models/ai-model.ts +81 -0
  146. package/src/models/{ai-decisions-choice-criteria-value.ts → ai-models.ts} +17 -2
  147. package/src/models/ai-price.ts +54 -0
  148. package/src/models/ai-receipt.ts +66 -0
  149. package/src/models/ai-routing-reward-request.ts +63 -0
  150. package/src/models/auto-automation-in.ts +6 -0
  151. package/src/models/auto-automation-patch.ts +6 -0
  152. package/src/models/auto-automation-run.ts +16 -1
  153. package/src/models/auto-automation.ts +6 -0
  154. package/src/models/auto-post-result.ts +42 -0
  155. package/src/models/auto-review-in.ts +42 -0
  156. package/src/models/git-workspace-view.ts +42 -0
  157. package/src/models/iam-user.ts +1 -1
  158. package/src/models/index.ts +14 -2
  159. package/src/models/provider-github-import-out.ts +6 -0
  160. package/src/models/provider-github-repo-item.ts +6 -0
  161. package/src/models/task-comment-list.ts +39 -0
  162. package/src/models/task-comment.ts +48 -0
  163. package/src/transport.ts +190 -0
  164. package/src/usage.ts +203 -0
  165. /package/dist/esm/models/{ai-decision-sides-false.js → ai-chat-in.js} +0 -0
  166. /package/dist/esm/models/{ai-decisions-choice-criteria-value.js → ai-chat.js} +0 -0
  167. /package/dist/models/{ai-decision-sides-false.js → ai-chat-in.js} +0 -0
  168. /package/dist/models/{ai-decisions-choice-criteria-value.js → ai-chat.js} +0 -0
@@ -333,6 +333,42 @@ const TaskApiAxiosParamCreator = function (configuration) {
333
333
  options: localVarRequestOptions,
334
334
  };
335
335
  },
336
+ /**
337
+ * Is one issue\'s conversation, oldest first, read as the caller. An issue that lives on GitHub names its home and is read there.
338
+ * @summary Is one issue\'s conversation, oldest first, read as the caller.
339
+ * @param {string} key Key is the board — the repository name, or an index board\'s key.
340
+ * @param {number} num Num is the issue\'s number on that board.
341
+ * @param {*} [options] Override http request option.
342
+ * @throws {RequiredError}
343
+ */
344
+ getTaskProjectsByKeyIssuesByNumComments: async (key, num, options = {}) => {
345
+ // verify required parameter 'key' is not null or undefined
346
+ (0, common_1.assertParamExists)('getTaskProjectsByKeyIssuesByNumComments', 'key', key);
347
+ // verify required parameter 'num' is not null or undefined
348
+ (0, common_1.assertParamExists)('getTaskProjectsByKeyIssuesByNumComments', 'num', num);
349
+ const localVarPath = `/v1/task/projects/{key}/issues/{num}/comments`
350
+ .replace(`{${"key"}}`, encodeURIComponent(String(key)))
351
+ .replace(`{${"num"}}`, encodeURIComponent(String(num)));
352
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
353
+ const localVarUrlObj = new URL(localVarPath, common_1.DUMMY_BASE_URL);
354
+ let baseOptions;
355
+ if (configuration) {
356
+ baseOptions = configuration.baseOptions;
357
+ }
358
+ const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options };
359
+ const localVarHeaderParameter = {};
360
+ const localVarQueryParameter = {};
361
+ // authentication bearer required
362
+ // http bearer authentication required
363
+ await (0, common_1.setBearerAuthToObject)(localVarHeaderParameter, configuration);
364
+ (0, common_1.setSearchParams)(localVarUrlObj, localVarQueryParameter);
365
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
366
+ localVarRequestOptions.headers = { ...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers };
367
+ return {
368
+ url: (0, common_1.toPathString)(localVarUrlObj),
369
+ options: localVarRequestOptions,
370
+ };
371
+ },
336
372
  /**
337
373
  * Summarises one room\'s work. The room is opaque here and is deliberately not resolved: this package cannot say whether a room exists — apps/team owns that document — so an unknown room answers an EMPTY board rather than a 404. That is the honest answer and the useful one: a channel that has never had an item filed in it and a channel id that was mistyped both have no work, and inventing a distinction would require this surface to hold a second copy of the room list (HIP-0523 §2 forbids it, and it would drift the first time a room was renamed). Tenancy is the validated principal\'s org and nothing else, so a caller cannot read another tenant\'s channel by naming its room.
338
374
  * @summary Summarises one room\'s work.
@@ -660,6 +696,20 @@ const TaskApiFp = function (configuration) {
660
696
  const localVarOperationServerBasePath = base_1.operationServerMap['TaskApi.getTaskProjectsByKeyIssuesByNum']?.[localVarOperationServerIndex]?.url;
661
697
  return (axios, basePath) => (0, common_1.createRequestFunction)(localVarAxiosArgs, axios_1.default, base_1.BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
662
698
  },
699
+ /**
700
+ * Is one issue\'s conversation, oldest first, read as the caller. An issue that lives on GitHub names its home and is read there.
701
+ * @summary Is one issue\'s conversation, oldest first, read as the caller.
702
+ * @param {string} key Key is the board — the repository name, or an index board\'s key.
703
+ * @param {number} num Num is the issue\'s number on that board.
704
+ * @param {*} [options] Override http request option.
705
+ * @throws {RequiredError}
706
+ */
707
+ async getTaskProjectsByKeyIssuesByNumComments(key, num, options) {
708
+ const localVarAxiosArgs = await localVarAxiosParamCreator.getTaskProjectsByKeyIssuesByNumComments(key, num, options);
709
+ const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
710
+ const localVarOperationServerBasePath = base_1.operationServerMap['TaskApi.getTaskProjectsByKeyIssuesByNumComments']?.[localVarOperationServerIndex]?.url;
711
+ return (axios, basePath) => (0, common_1.createRequestFunction)(localVarAxiosArgs, axios_1.default, base_1.BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
712
+ },
663
713
  /**
664
714
  * Summarises one room\'s work. The room is opaque here and is deliberately not resolved: this package cannot say whether a room exists — apps/team owns that document — so an unknown room answers an EMPTY board rather than a 404. That is the honest answer and the useful one: a channel that has never had an item filed in it and a channel id that was mistyped both have no work, and inventing a distinction would require this surface to hold a second copy of the room list (HIP-0523 §2 forbids it, and it would drift the first time a room was renamed). Tenancy is the validated principal\'s org and nothing else, so a caller cannot read another tenant\'s channel by naming its room.
665
715
  * @summary Summarises one room\'s work.
@@ -820,6 +870,16 @@ const TaskApiFactory = function (configuration, basePath, axios) {
820
870
  getTaskProjectsByKeyIssuesByNum(requestParameters, options) {
821
871
  return localVarFp.getTaskProjectsByKeyIssuesByNum(requestParameters.key, requestParameters.num, options).then((request) => request(axios, basePath));
822
872
  },
873
+ /**
874
+ * Is one issue\'s conversation, oldest first, read as the caller. An issue that lives on GitHub names its home and is read there.
875
+ * @summary Is one issue\'s conversation, oldest first, read as the caller.
876
+ * @param {TaskApiGetTaskProjectsByKeyIssuesByNumCommentsRequest} requestParameters Request parameters.
877
+ * @param {*} [options] Override http request option.
878
+ * @throws {RequiredError}
879
+ */
880
+ getTaskProjectsByKeyIssuesByNumComments(requestParameters, options) {
881
+ return localVarFp.getTaskProjectsByKeyIssuesByNumComments(requestParameters.key, requestParameters.num, options).then((request) => request(axios, basePath));
882
+ },
823
883
  /**
824
884
  * Summarises one room\'s work. The room is opaque here and is deliberately not resolved: this package cannot say whether a room exists — apps/team owns that document — so an unknown room answers an EMPTY board rather than a 404. That is the honest answer and the useful one: a channel that has never had an item filed in it and a channel id that was mistyped both have no work, and inventing a distinction would require this surface to hold a second copy of the room list (HIP-0523 §2 forbids it, and it would drift the first time a room was renamed). Tenancy is the validated principal\'s org and nothing else, so a caller cannot read another tenant\'s channel by naming its room.
825
885
  * @summary Summarises one room\'s work.
@@ -965,6 +1025,17 @@ class TaskApi extends base_1.BaseAPI {
965
1025
  getTaskProjectsByKeyIssuesByNum(requestParameters, options) {
966
1026
  return (0, exports.TaskApiFp)(this.configuration).getTaskProjectsByKeyIssuesByNum(requestParameters.key, requestParameters.num, options).then((request) => request(this.axios, this.basePath));
967
1027
  }
1028
+ /**
1029
+ * Is one issue\'s conversation, oldest first, read as the caller. An issue that lives on GitHub names its home and is read there.
1030
+ * @summary Is one issue\'s conversation, oldest first, read as the caller.
1031
+ * @param {TaskApiGetTaskProjectsByKeyIssuesByNumCommentsRequest} requestParameters Request parameters.
1032
+ * @param {*} [options] Override http request option.
1033
+ * @throws {RequiredError}
1034
+ * @memberof TaskApi
1035
+ */
1036
+ getTaskProjectsByKeyIssuesByNumComments(requestParameters, options) {
1037
+ return (0, exports.TaskApiFp)(this.configuration).getTaskProjectsByKeyIssuesByNumComments(requestParameters.key, requestParameters.num, options).then((request) => request(this.axios, this.basePath));
1038
+ }
968
1039
  /**
969
1040
  * Summarises one room\'s work. The room is opaque here and is deliberately not resolved: this package cannot say whether a room exists — apps/team owns that document — so an unknown room answers an EMPTY board rather than a 404. That is the honest answer and the useful one: a channel that has never had an item filed in it and a channel id that was mistyped both have no work, and inventing a distinction would require this surface to hold a second copy of the room list (HIP-0523 §2 forbids it, and it would drift the first time a room was renamed). Tenancy is the validated principal\'s org and nothing else, so a caller cannot read another tenant\'s channel by naming its room.
970
1041
  * @summary Summarises one room\'s work.
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Configuration } from './configuration';
1
+ import { Configuration } from './transport';
2
2
  import { Audit } from './audit';
3
3
  import { Budget } from './budget';
4
4
  import { Graph } from './graph';
@@ -56,7 +56,8 @@ export declare class Client {
56
56
  /**
57
57
  * A Configuration carrying this client's identity, for the generated *Api
58
58
  * classes. The `accessToken` reader is a function, so every generated call
59
- * mints or re-uses through the same cache the six use.
59
+ * mints or re-uses through the same cache the six use, and a usage refusal
60
+ * arrives as its typed error (transport.ts).
60
61
  */
61
62
  get configuration(): Configuration;
62
63
  /** A live access token, minting one when what is held is gone or nearly so. */
package/dist/client.js CHANGED
@@ -15,7 +15,7 @@
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.Client = void 0;
17
17
  const answer_1 = require("./answer");
18
- const configuration_1 = require("./configuration");
18
+ const transport_1 = require("./transport");
19
19
  const audit_1 = require("./audit");
20
20
  const budget_1 = require("./budget");
21
21
  const graph_1 = require("./graph");
@@ -69,10 +69,11 @@ class Client {
69
69
  /**
70
70
  * A Configuration carrying this client's identity, for the generated *Api
71
71
  * classes. The `accessToken` reader is a function, so every generated call
72
- * mints or re-uses through the same cache the six use.
72
+ * mints or re-uses through the same cache the six use, and a usage refusal
73
+ * arrives as its typed error (transport.ts).
73
74
  */
74
75
  get configuration() {
75
- return new configuration_1.Configuration({ basePath: this.base, accessToken: () => this.token() });
76
+ return new transport_1.Configuration({ basePath: this.base, accessToken: () => this.token() });
76
77
  }
77
78
  /** A live access token, minting one when what is held is gone or nearly so. */
78
79
  async token() {
@@ -9,6 +9,7 @@
9
9
  // transport failure, a server fault. There is nothing in those for a caller to
10
10
  // read, so there is no arm for them.
11
11
  import { list, num, obj, str } from './read';
12
+ import { limited } from './usage';
12
13
  /**
13
14
  * An outcome with no decision in it.
14
15
  *
@@ -51,15 +52,17 @@ const refusals = new Set(['spend_cap_exceeded', 'insufficient_balance']);
51
52
  function refusal(body) {
52
53
  const b = obj(body);
53
54
  // RFC 9457 spells the code `code` and the sentence `detail`; the spend gate's
54
- // own body spells them `error` and `message` and adds `product` and `cure[]`.
55
- // Its own `reason` — "unpaid", "unresolved" — names the admit leg that failed
56
- // rather than explaining anything to a person, so it is not read. One reader,
57
- // named fallbacks — not two paths — so it keeps working unchanged when cloud
58
- // settles on the envelope alone.
55
+ // own body spells them `error` and `message` and adds `product` and `cure[]`;
56
+ // the AI gateway's OpenAI envelope nests `code` and `message` under `error`.
57
+ // The spend gate's `reason` — "unpaid", "unresolved" — names the admit leg that
58
+ // failed rather than explaining anything to a person, so it is not read. One
59
+ // reader, named fallbacks — not three paths — so it keeps working unchanged
60
+ // when cloud settles on one envelope.
61
+ const e = obj(b['error']);
59
62
  const product = str(b['product']);
60
63
  return {
61
- code: str(b['code']) || str(b['error']),
62
- reason: str(b['detail']) || str(b['message']),
64
+ code: str(b['code']) || str(b['error']) || str(e['code']),
65
+ reason: str(b['detail']) || str(b['message']) || str(e['message']),
63
66
  ...(product ? { product } : {}),
64
67
  cures: list(b['cure']).map((c) => {
65
68
  const cure = obj(c);
@@ -100,14 +103,21 @@ export function arm(r, read) {
100
103
  if (r.status === 402 || (r.status === 403 && refusals.has(said.code))) {
101
104
  return { status: 'denied', ...said, request: r.request };
102
105
  }
103
- throw new Fault(r.status, said.code, said.reason || `HTTP ${r.status}`, r.request);
106
+ throw fault(r, said);
104
107
  }
105
108
  /** A read no gate refuses: the value, or a [Fault] because nothing was decided. */
106
109
  export function value(r, read) {
107
110
  if (r.status >= 200 && r.status < 300)
108
111
  return read(r.body);
109
- const said = refusal(r.body);
110
- throw new Fault(r.status, said.code, said.reason || `HTTP ${r.status}`, r.request);
112
+ throw fault(r, refusal(r.body));
113
+ }
114
+ /**
115
+ * What a call that decided nothing throws: the usage refusal the body names
116
+ * (usage.ts), or a [Fault]. What [arm] reads as [Denied] never reaches here.
117
+ */
118
+ function fault(r, said) {
119
+ return (limited(r.status, r.body, r.request || undefined) ??
120
+ new Fault(r.status, said.code, said.reason || `HTTP ${r.status}`, r.request));
111
121
  }
112
122
  /** `{data, total}` — the page shape every listing on this wire answers with. */
113
123
  export function page(body, read) {