@superbee/core 0.2.0-pre.17 → 0.2.0-pre.19

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 (202) hide show
  1. package/README.md +515 -1
  2. package/dist/blob-journal.d.ts +187 -2
  3. package/dist/blob-journal.d.ts.map +1 -1
  4. package/dist/blob-journal.js +377 -5
  5. package/dist/blob-journal.js.map +1 -1
  6. package/dist/body-replace-guards.d.ts +50 -0
  7. package/dist/body-replace-guards.d.ts.map +1 -0
  8. package/dist/body-replace-guards.js +158 -0
  9. package/dist/body-replace-guards.js.map +1 -0
  10. package/dist/builtin-recipes/content.d.ts +93 -0
  11. package/dist/builtin-recipes/content.d.ts.map +1 -0
  12. package/dist/builtin-recipes/content.js +288 -0
  13. package/dist/builtin-recipes/content.js.map +1 -0
  14. package/dist/builtin-recipes.d.ts +10 -0
  15. package/dist/builtin-recipes.d.ts.map +1 -0
  16. package/dist/builtin-recipes.js +97 -0
  17. package/dist/builtin-recipes.js.map +1 -0
  18. package/dist/code-point-order.d.ts +8 -0
  19. package/dist/code-point-order.d.ts.map +1 -0
  20. package/dist/code-point-order.js +20 -0
  21. package/dist/code-point-order.js.map +1 -0
  22. package/dist/connectors.d.ts +223 -0
  23. package/dist/connectors.d.ts.map +1 -0
  24. package/dist/connectors.js +1143 -0
  25. package/dist/connectors.js.map +1 -0
  26. package/dist/document-field-actions.d.ts +18 -0
  27. package/dist/document-field-actions.d.ts.map +1 -1
  28. package/dist/document-field-actions.js +91 -29
  29. package/dist/document-field-actions.js.map +1 -1
  30. package/dist/document-mutation.d.ts +7 -9
  31. package/dist/document-mutation.d.ts.map +1 -1
  32. package/dist/document-mutation.js +16 -16
  33. package/dist/document-mutation.js.map +1 -1
  34. package/dist/file-journaled-backend.d.ts +31 -5
  35. package/dist/file-journaled-backend.d.ts.map +1 -1
  36. package/dist/file-journaled-backend.js +131 -118
  37. package/dist/file-journaled-backend.js.map +1 -1
  38. package/dist/hosted-client/blob-delivery.d.ts +6 -0
  39. package/dist/hosted-client/blob-delivery.d.ts.map +1 -1
  40. package/dist/hosted-client/blob-delivery.js +23 -1
  41. package/dist/hosted-client/blob-delivery.js.map +1 -1
  42. package/dist/hosted-client/blob-write.d.ts +386 -0
  43. package/dist/hosted-client/blob-write.d.ts.map +1 -0
  44. package/dist/hosted-client/blob-write.js +770 -0
  45. package/dist/hosted-client/blob-write.js.map +1 -0
  46. package/dist/hosted-client/client.d.ts +64 -0
  47. package/dist/hosted-client/client.d.ts.map +1 -1
  48. package/dist/hosted-client/client.js +31 -0
  49. package/dist/hosted-client/client.js.map +1 -1
  50. package/dist/hosted-client/directory.d.ts +46 -0
  51. package/dist/hosted-client/directory.d.ts.map +1 -0
  52. package/dist/hosted-client/directory.js +74 -0
  53. package/dist/hosted-client/directory.js.map +1 -0
  54. package/dist/hosted-client/errors.d.ts +10 -0
  55. package/dist/hosted-client/errors.d.ts.map +1 -1
  56. package/dist/hosted-client/errors.js +13 -0
  57. package/dist/hosted-client/errors.js.map +1 -1
  58. package/dist/hosted-client/inbox.d.ts +320 -0
  59. package/dist/hosted-client/inbox.d.ts.map +1 -0
  60. package/dist/hosted-client/inbox.js +379 -0
  61. package/dist/hosted-client/inbox.js.map +1 -0
  62. package/dist/hosted-client/index.d.ts +11 -4
  63. package/dist/hosted-client/index.d.ts.map +1 -1
  64. package/dist/hosted-client/index.js +11 -4
  65. package/dist/hosted-client/index.js.map +1 -1
  66. package/dist/hosted-client/journal.d.ts +103 -0
  67. package/dist/hosted-client/journal.d.ts.map +1 -0
  68. package/dist/hosted-client/journal.js +464 -0
  69. package/dist/hosted-client/journal.js.map +1 -0
  70. package/dist/hosted-client/node.d.ts +5 -1
  71. package/dist/hosted-client/node.d.ts.map +1 -1
  72. package/dist/hosted-client/node.js +6 -1
  73. package/dist/hosted-client/node.js.map +1 -1
  74. package/dist/hosted-client/write.d.ts +18 -1
  75. package/dist/hosted-client/write.d.ts.map +1 -1
  76. package/dist/hosted-client/write.js +24 -7
  77. package/dist/hosted-client/write.js.map +1 -1
  78. package/dist/hosted-transport/carrier.d.ts +10 -0
  79. package/dist/hosted-transport/carrier.d.ts.map +1 -1
  80. package/dist/hosted-transport/carrier.js +22 -2
  81. package/dist/hosted-transport/carrier.js.map +1 -1
  82. package/dist/index.d.ts +4 -1
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +3 -1
  85. package/dist/index.js.map +1 -1
  86. package/dist/kind-authoring.d.ts +170 -0
  87. package/dist/kind-authoring.d.ts.map +1 -0
  88. package/dist/kind-authoring.js +451 -0
  89. package/dist/kind-authoring.js.map +1 -0
  90. package/dist/kind-conformance-error.d.ts +15 -0
  91. package/dist/kind-conformance-error.d.ts.map +1 -0
  92. package/dist/kind-conformance-error.js +20 -0
  93. package/dist/kind-conformance-error.js.map +1 -0
  94. package/dist/kinds.d.ts +2 -0
  95. package/dist/kinds.d.ts.map +1 -1
  96. package/dist/kinds.js +7 -0
  97. package/dist/kinds.js.map +1 -1
  98. package/dist/recipe-lifecycle/stamp.d.ts +11 -0
  99. package/dist/recipe-lifecycle/stamp.d.ts.map +1 -1
  100. package/dist/recipe-lifecycle/stamp.js +6 -0
  101. package/dist/recipe-lifecycle/stamp.js.map +1 -1
  102. package/dist/record-overlay/apply.d.ts.map +1 -1
  103. package/dist/record-overlay/apply.js +52 -15
  104. package/dist/record-overlay/apply.js.map +1 -1
  105. package/dist/record-overlay/canonical.d.ts +8 -0
  106. package/dist/record-overlay/canonical.d.ts.map +1 -1
  107. package/dist/record-overlay/canonical.js +16 -0
  108. package/dist/record-overlay/canonical.js.map +1 -1
  109. package/dist/record-overlay/errors.d.ts +7 -3
  110. package/dist/record-overlay/errors.d.ts.map +1 -1
  111. package/dist/record-overlay/errors.js +7 -3
  112. package/dist/record-overlay/errors.js.map +1 -1
  113. package/dist/record-overlay/plan.d.ts.map +1 -1
  114. package/dist/record-overlay/plan.js +2 -1
  115. package/dist/record-overlay/plan.js.map +1 -1
  116. package/dist/record-overlay/policy.d.ts +10 -1
  117. package/dist/record-overlay/policy.d.ts.map +1 -1
  118. package/dist/record-overlay/policy.js +33 -14
  119. package/dist/record-overlay/policy.js.map +1 -1
  120. package/dist/record-overlay/types.d.ts +5 -0
  121. package/dist/record-overlay/types.d.ts.map +1 -1
  122. package/dist/search/contract.d.ts +151 -0
  123. package/dist/search/contract.d.ts.map +1 -0
  124. package/dist/search/contract.js +78 -0
  125. package/dist/search/contract.js.map +1 -0
  126. package/dist/search/errors.d.ts +30 -0
  127. package/dist/search/errors.d.ts.map +1 -0
  128. package/dist/search/errors.js +50 -0
  129. package/dist/search/errors.js.map +1 -0
  130. package/dist/search/identity.d.ts +12 -0
  131. package/dist/search/identity.d.ts.map +1 -0
  132. package/dist/search/identity.js +90 -0
  133. package/dist/search/identity.js.map +1 -0
  134. package/dist/search/index.d.ts +15 -0
  135. package/dist/search/index.d.ts.map +1 -0
  136. package/dist/search/index.js +14 -0
  137. package/dist/search/index.js.map +1 -0
  138. package/dist/search/memory-source.d.ts +25 -0
  139. package/dist/search/memory-source.d.ts.map +1 -0
  140. package/dist/search/memory-source.js +230 -0
  141. package/dist/search/memory-source.js.map +1 -0
  142. package/dist/search/rank.d.ts +34 -0
  143. package/dist/search/rank.d.ts.map +1 -0
  144. package/dist/search/rank.js +129 -0
  145. package/dist/search/rank.js.map +1 -0
  146. package/dist/search/row-text.d.ts +38 -0
  147. package/dist/search/row-text.d.ts.map +1 -0
  148. package/dist/search/row-text.js +88 -0
  149. package/dist/search/row-text.js.map +1 -0
  150. package/dist/search/search.d.ts +28 -0
  151. package/dist/search/search.d.ts.map +1 -0
  152. package/dist/search/search.js +240 -0
  153. package/dist/search/search.js.map +1 -0
  154. package/dist/search/source.d.ts +67 -0
  155. package/dist/search/source.d.ts.map +1 -0
  156. package/dist/search/source.js +2 -0
  157. package/dist/search/source.js.map +1 -0
  158. package/dist/search/text.d.ts +47 -0
  159. package/dist/search/text.d.ts.map +1 -0
  160. package/dist/search/text.js +148 -0
  161. package/dist/search/text.js.map +1 -0
  162. package/dist/source-engine/guard.d.ts +82 -0
  163. package/dist/source-engine/guard.d.ts.map +1 -0
  164. package/dist/source-engine/guard.js +396 -0
  165. package/dist/source-engine/guard.js.map +1 -0
  166. package/dist/source-engine/index.d.ts +24 -0
  167. package/dist/source-engine/index.d.ts.map +1 -0
  168. package/dist/source-engine/index.js +20 -0
  169. package/dist/source-engine/index.js.map +1 -0
  170. package/dist/source-engine/machine-state.d.ts +74 -0
  171. package/dist/source-engine/machine-state.d.ts.map +1 -0
  172. package/dist/source-engine/machine-state.js +48 -0
  173. package/dist/source-engine/machine-state.js.map +1 -0
  174. package/dist/source-engine/observe.d.ts +18 -0
  175. package/dist/source-engine/observe.d.ts.map +1 -0
  176. package/dist/source-engine/observe.js +598 -0
  177. package/dist/source-engine/observe.js.map +1 -0
  178. package/dist/source-engine/robots.d.ts +53 -0
  179. package/dist/source-engine/robots.d.ts.map +1 -0
  180. package/dist/source-engine/robots.js +158 -0
  181. package/dist/source-engine/robots.js.map +1 -0
  182. package/dist/source-engine/types.d.ts +285 -0
  183. package/dist/source-engine/types.d.ts.map +1 -0
  184. package/dist/source-engine/types.js +2 -0
  185. package/dist/source-engine/types.js.map +1 -0
  186. package/dist/source-harness/conformance.d.ts +16 -0
  187. package/dist/source-harness/conformance.d.ts.map +1 -0
  188. package/dist/source-harness/conformance.js +265 -0
  189. package/dist/source-harness/conformance.js.map +1 -0
  190. package/dist/source-harness/fixture.d.ts +95 -0
  191. package/dist/source-harness/fixture.d.ts.map +1 -0
  192. package/dist/source-harness/fixture.js +261 -0
  193. package/dist/source-harness/fixture.js.map +1 -0
  194. package/dist/source-harness/index.d.ts +22 -0
  195. package/dist/source-harness/index.d.ts.map +1 -0
  196. package/dist/source-harness/index.js +19 -0
  197. package/dist/source-harness/index.js.map +1 -0
  198. package/dist/source-harness/peer.d.ts +74 -0
  199. package/dist/source-harness/peer.d.ts.map +1 -0
  200. package/dist/source-harness/peer.js +106 -0
  201. package/dist/source-harness/peer.js.map +1 -0
  202. package/package.json +25 -1
@@ -0,0 +1,240 @@
1
+ /**
2
+ * One `documents.search.v1` request over a source. Query normalization, the 16-term cap, `auto`
3
+ * matching (all terms, then the any-term fallback without conversational terms) and the guidance
4
+ * text are portal-webmcp 0.3.1's `superbee_search_documents`; cursors, facets, the page budget and
5
+ * the result shape are this contract's. Every refusal is a `SearchInputError` with a fixed reason.
6
+ */
7
+ import { sha256HexOfUtf8 } from "../sha256.js";
8
+ import { SEARCH_ALGORITHM, SEARCH_FACETS, SEARCH_GUIDANCE, SEARCH_LIMITS, SEARCH_MATCHES, } from "./contract.js";
9
+ import { SearchBroadQueryError, SearchInputError, stopIfAsked } from "./errors.js";
10
+ import { base64UrlDecode, base64UrlEncode, canonicalJson } from "./identity.js";
11
+ import { excerptOf, facetsOf, rankEvidence } from "./rank.js";
12
+ import { normalizeQuery, relaxQuery, utf8, utf8ByteLength } from "./text.js";
13
+ const CURSOR_VERSION = 1;
14
+ const REQUEST_MEMBERS = new Set(["query", "match", "type", "tag", "prefix", "limit", "cursor", "facets"]);
15
+ /** A lone surrogate: matched by code unit in memory, but it has no UTF-8 form a native index can bind. */
16
+ const LONE_SURROGATE = /[\uD800-\uDFFF]/u;
17
+ function optionalFilter(value, maxBytes = SEARCH_LIMITS.maxFilterBytes) {
18
+ if (value === undefined)
19
+ return undefined;
20
+ if (typeof value !== "string" || value === "" || utf8ByteLength(value) > maxBytes || LONE_SURROGATE.test(value))
21
+ throw new SearchInputError("filter");
22
+ return value;
23
+ }
24
+ function evidenceInstanceBound(value) {
25
+ if (value === undefined)
26
+ return SEARCH_LIMITS.maxEvidenceInstances;
27
+ if (!Number.isSafeInteger(value) || value < 1)
28
+ throw new TypeError("maxEvidenceInstances must be a positive integer");
29
+ return Math.min(value, SEARCH_LIMITS.maxEvidenceInstances);
30
+ }
31
+ const isCount = (value) => Number.isSafeInteger(value) && value >= 0;
32
+ /** The contract's checks on every member except the cursor's binding, in one order. */
33
+ function checkRequest(request) {
34
+ const raw = request?.query;
35
+ if (typeof raw !== "string" || utf8ByteLength(raw) > SEARCH_LIMITS.maxQueryBytes)
36
+ throw new SearchInputError("query");
37
+ const query = normalizeQuery(raw);
38
+ if (query.terms.length === 0)
39
+ throw new SearchInputError("empty-query");
40
+ if (query.terms.length > SEARCH_LIMITS.maxQueryTerms)
41
+ throw new SearchInputError("too-many-query-terms");
42
+ const requestedMatch = request.match ?? "auto";
43
+ if (!SEARCH_MATCHES.includes(requestedMatch))
44
+ throw new SearchInputError("match");
45
+ const type = optionalFilter(request.type);
46
+ const tag = optionalFilter(request.tag);
47
+ const prefix = optionalFilter(request.prefix, SEARCH_LIMITS.maxPrefixBytes);
48
+ const filters = {
49
+ ...(type === undefined ? {} : { type }),
50
+ ...(tag === undefined ? {} : { tag }),
51
+ ...(prefix === undefined ? {} : { prefix }),
52
+ };
53
+ const limit = request.limit ?? SEARCH_LIMITS.defaultRows;
54
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > SEARCH_LIMITS.maxRows)
55
+ throw new SearchInputError("limit");
56
+ const wanted = new Set();
57
+ if (request.facets !== undefined) {
58
+ if (!Array.isArray(request.facets) || request.facets.length > SEARCH_FACETS.length)
59
+ throw new SearchInputError("facets");
60
+ for (const facet of request.facets) {
61
+ if (!SEARCH_FACETS.includes(facet) || wanted.has(facet))
62
+ throw new SearchInputError("facets");
63
+ wanted.add(facet);
64
+ }
65
+ }
66
+ return { query, requestedMatch, type, tag, prefix, filters, limit, wanted };
67
+ }
68
+ function cursorText(cursor) {
69
+ if (typeof cursor !== "string" || cursor === "" || utf8ByteLength(cursor) > SEARCH_LIMITS.maxCursorBytes)
70
+ throw new SearchInputError("cursor");
71
+ return cursor;
72
+ }
73
+ /**
74
+ * The contract's checks without a schema library: a plain request object with only the contract's
75
+ * members, each within its bounds. Returns a copy holding the members present. A cursor's binding
76
+ * is checked when it is used, against the corpus it continues.
77
+ */
78
+ export function validateSearchRequest(input) {
79
+ if (input === null || typeof input !== "object" || Array.isArray(input))
80
+ throw new SearchInputError("request");
81
+ for (const member of Object.keys(input))
82
+ if (!REQUEST_MEMBERS.has(member))
83
+ throw new SearchInputError("request");
84
+ const request = input;
85
+ checkRequest(request);
86
+ if (request.cursor !== undefined)
87
+ cursorText(request.cursor);
88
+ return {
89
+ query: request.query,
90
+ ...(request.match === undefined ? {} : { match: request.match }),
91
+ ...(request.type === undefined ? {} : { type: request.type }),
92
+ ...(request.tag === undefined ? {} : { tag: request.tag }),
93
+ ...(request.prefix === undefined ? {} : { prefix: request.prefix }),
94
+ ...(request.limit === undefined ? {} : { limit: request.limit }),
95
+ ...(request.cursor === undefined ? {} : { cursor: request.cursor }),
96
+ ...(request.facets === undefined ? {} : { facets: [...request.facets] }),
97
+ };
98
+ }
99
+ function bindingOf(corpusKey, scope, state) {
100
+ return sha256HexOfUtf8(canonicalJson({
101
+ algorithm: SEARCH_ALGORITHM,
102
+ corpusKey,
103
+ scope: scope ?? null,
104
+ ...state,
105
+ }));
106
+ }
107
+ function encodeCursor(binding, position) {
108
+ return base64UrlEncode(utf8(canonicalJson({ b: binding, p: position, v: CURSOR_VERSION })));
109
+ }
110
+ /** The position a cursor continues from; it must carry this request's binding and lie inside the hits. */
111
+ function decodeCursor(cursor, binding, total) {
112
+ const bytes = base64UrlDecode(cursorText(cursor));
113
+ let parsed;
114
+ try {
115
+ parsed = bytes && JSON.parse(new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes));
116
+ }
117
+ catch {
118
+ throw new SearchInputError("cursor");
119
+ }
120
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
121
+ throw new SearchInputError("cursor");
122
+ const body = parsed;
123
+ const keys = Object.keys(body).sort();
124
+ if (keys.join(",") !== "b,p,v" || body.v !== CURSOR_VERSION || body.b !== binding)
125
+ throw new SearchInputError("cursor");
126
+ // A cursor is minted only while hits remain, so a position at or past the end was forged or replayed.
127
+ const position = body.p;
128
+ if (!Number.isSafeInteger(position) || position < 1 || position >= total)
129
+ throw new SearchInputError("cursor");
130
+ return position;
131
+ }
132
+ /**
133
+ * Runs one request over a source. Throws `SearchInputError` for a request outside the contract
134
+ * (including a cursor minted for another corpus, scope, query, match or filters),
135
+ * `SearchBroadQueryError` when the request's terms exceed `maxEvidenceInstances`, `SearchLimitError`
136
+ * as the source does, and stops as `stop` asks.
137
+ */
138
+ export async function searchDocuments(source, request, scope = {}, stop, options = {}) {
139
+ if (typeof source?.evidence !== "function" || typeof source.text !== "function")
140
+ throw new TypeError("searchDocuments needs a SearchSource");
141
+ const { query, requestedMatch, type, tag, prefix, filters, limit, wanted } = checkRequest(request);
142
+ const maxInstances = evidenceInstanceBound(options.maxEvidenceInstances);
143
+ stopIfAsked(stop);
144
+ const batch = await source.evidence(query.terms, filters, { maxInstances }, stop);
145
+ stopIfAsked(stop);
146
+ const size = batch?.size;
147
+ if (typeof batch?.key !== "string" ||
148
+ batch.key === "" ||
149
+ !Array.isArray(batch.documents) ||
150
+ !isCount(batch.volume) ||
151
+ ![size?.documents, size?.indexed, size?.skipped, size?.reindexPending].every(isCount))
152
+ throw new TypeError("the search source answered a malformed evidence batch");
153
+ // The same bound on every source, whether or not the source stopped before its walk.
154
+ if (batch.volume > maxInstances)
155
+ throw new SearchBroadQueryError(maxInstances, batch.volume);
156
+ let effectiveMatch = requestedMatch === "any" ? "any" : "all";
157
+ let effectiveQuery = query;
158
+ let ignoredTerms = [];
159
+ let fallbackUsed = false;
160
+ let hits = rankEvidence(batch.documents, effectiveQuery, filters, effectiveMatch, stop);
161
+ if (requestedMatch === "auto" && hits.length === 0 && query.terms.length > 1) {
162
+ // The relaxed terms are a subset of the terms the evidence answered, so one read serves both.
163
+ const relaxed = relaxQuery(query);
164
+ effectiveQuery = relaxed.query;
165
+ ignoredTerms = relaxed.ignoredTerms;
166
+ effectiveMatch = "any";
167
+ fallbackUsed = true;
168
+ hits = rankEvidence(batch.documents, effectiveQuery, filters, effectiveMatch, stop);
169
+ }
170
+ const binding = bindingOf(batch.key, scope?.scope, {
171
+ query: query.phrase,
172
+ match: requestedMatch,
173
+ type: type ?? null,
174
+ tag: tag ?? null,
175
+ // Absent when unused, so a request without a prefix binds as it did before the filter existed.
176
+ prefix,
177
+ });
178
+ const start = request.cursor === undefined ? 0 : decodeCursor(request.cursor, binding, hits.length);
179
+ const page = hits.slice(start, start + limit);
180
+ const texts = page.length === 0
181
+ ? new Map()
182
+ : await source.text(page.map(({ evidence }) => ({ id: evidence.id, version: evidence.version })));
183
+ stopIfAsked(stop);
184
+ const rows = page.map((hit) => {
185
+ const { evidence } = hit;
186
+ return {
187
+ id: evidence.id,
188
+ version: evidence.version,
189
+ ...(evidence.title === undefined ? {} : { title: evidence.title }),
190
+ ...(evidence.type === undefined ? {} : { type: evidence.type }),
191
+ tags: [...evidence.tags],
192
+ score: hit.score,
193
+ matchedTerms: hit.matchedTerms.map(({ term, fields }) => ({ term, fields: [...fields] })),
194
+ excerpt: excerptOf(hit, texts.get(evidence.id), effectiveQuery, SEARCH_LIMITS.excerptBytes),
195
+ };
196
+ });
197
+ const answer = (count) => ({
198
+ hits: rows.slice(0, count),
199
+ query: {
200
+ requestedMatch,
201
+ effectiveMatch,
202
+ fallbackUsed,
203
+ terms: [...effectiveQuery.terms],
204
+ ...(ignoredTerms.length === 0 ? {} : { ignoredTerms: [...ignoredTerms] }),
205
+ },
206
+ total: hits.length,
207
+ ...(wanted.size === 0 ? {} : { facets: facetsOf(hits, wanted) }),
208
+ ...(start + count < hits.length ? { nextCursor: encodeCursor(binding, start + count) } : {}),
209
+ corpus: {
210
+ documents: size.documents,
211
+ indexed: size.indexed,
212
+ skipped: size.skipped,
213
+ reindexPending: size.reindexPending,
214
+ },
215
+ ...(hits.length === 0
216
+ ? {
217
+ guidance: effectiveMatch === "all" && effectiveQuery.terms.length > 1 ? SEARCH_GUIDANCE.all : SEARCH_GUIDANCE.any,
218
+ }
219
+ : {}),
220
+ });
221
+ // A page that does not fit the host's answer budget ends early, with a cursor at the cut (as
222
+ // portal-webmcp's pages do), so a long question at limit 50 still answers. At least one hit is kept:
223
+ // a single hit too large for the budget is the host's refusal to make.
224
+ let count = rows.length;
225
+ let result = answer(count);
226
+ const budget = options.maxResultBytes;
227
+ if (budget !== undefined && count > 1 && utf8ByteLength(JSON.stringify(result)) > budget) {
228
+ const sizes = rows.map((row) => utf8ByteLength(JSON.stringify(row)) + 1);
229
+ let size = utf8ByteLength(JSON.stringify(answer(0))) + utf8ByteLength(encodeCursor(binding, start)) + 16;
230
+ count = 0;
231
+ while (count < rows.length && size + sizes[count] <= budget)
232
+ size += sizes[count++];
233
+ count = Math.max(1, count);
234
+ result = answer(count);
235
+ while (count > 1 && utf8ByteLength(JSON.stringify(result)) > budget)
236
+ result = answer(--count);
237
+ }
238
+ return result;
239
+ }
240
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The seam a backend implements so the engine can search it. A source answers evidence for the
3
+ * query's terms in one consistent read and the text of the page's hits for excerpts; the engine
4
+ * ranks, pages and facets every source with the same code, so two sources that answer the same
5
+ * evidence for the same documents give byte-identical results.
6
+ */
7
+ import type { SearchFiltersV1, SearchMatchFieldV1, SearchStopV1 } from "./contract.js";
8
+ /** What one indexed document holds of the query's terms, plus the fields ranking and facets read. */
9
+ export interface SearchEvidenceV1 {
10
+ readonly id: string;
11
+ readonly version: string;
12
+ readonly title?: string;
13
+ readonly type?: string;
14
+ /** Declared string tags, in document order. */
15
+ readonly tags: readonly string[];
16
+ readonly titlePhrase: string;
17
+ readonly idPhrase: string;
18
+ /** term -> the fields holding it and its body occurrences, capped at BODY_OCCURRENCE_CAP. Only
19
+ * terms the document holds appear. */
20
+ readonly terms: ReadonlyMap<string, {
21
+ readonly fields: readonly SearchMatchFieldV1[];
22
+ readonly bodyOccurrences: number;
23
+ }>;
24
+ }
25
+ /** The sizes of what a source searched, reported as the result's `corpus`. */
26
+ export interface SearchCorpusSizeV1 {
27
+ /** Every document of the corpus. */
28
+ readonly documents: number;
29
+ /** Documents the source searches, reindexPending included. */
30
+ readonly indexed: number;
31
+ /** Documents the index cannot hold (over SEARCH_LIMITS.maxTermsPerDocument body terms, or a
32
+ * backend's own row bound), left out and counted. */
33
+ readonly skipped: number;
34
+ /** Indexed documents served at an older text version, awaiting re-derivation. */
35
+ readonly reindexPending: number;
36
+ }
37
+ /** What the engine allows one evidence read: a source that can stops before walking anything. */
38
+ export interface SearchEvidenceBoundsV1 {
39
+ /** The most capped term instances the terms may hold; over it, `documents` is empty. */
40
+ readonly maxInstances: number;
41
+ }
42
+ export interface SearchEvidenceBatchV1 {
43
+ /** Identity of what was searched: a snapshot digest, a heads digest, or a revision. Cursors bind to it. */
44
+ readonly key: string;
45
+ readonly size: SearchCorpusSizeV1;
46
+ /** Sum over the terms of their capped instance counts (searchRowText's `instances`) across the
47
+ * indexed documents, before the filters. */
48
+ readonly volume: number;
49
+ /** Every indexed document holding at least one of the terms after the exact filters, once each.
50
+ * Empty when `volume` exceeds the bound. */
51
+ readonly documents: readonly SearchEvidenceV1[];
52
+ }
53
+ export interface SearchTextV1 {
54
+ readonly description: string;
55
+ readonly body: string;
56
+ }
57
+ export interface SearchSource {
58
+ /** One consistent read: identity, sizes, the volume pre-check and the evidence for `terms` after
59
+ * the exact filters. */
60
+ evidence(terms: readonly string[], filters: SearchFiltersV1, bounds: SearchEvidenceBoundsV1, stop?: SearchStopV1): Promise<SearchEvidenceBatchV1>;
61
+ /** Description and body of the page's hits, at the evidence's version, for excerpts only. */
62
+ text(hits: readonly {
63
+ readonly id: string;
64
+ readonly version: string;
65
+ }[]): Promise<ReadonlyMap<string, SearchTextV1>>;
66
+ }
67
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/search/source.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEvF,qGAAqG;AACrG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;0CACsC;IACtC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;QAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3H;AAED,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;yDACqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,iGAAiG;AACjG,MAAM,WAAW,sBAAsB;IACrC,wFAAwF;IACxF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,2GAA2G;IAC3G,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC;gDAC4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;gDAC4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B;4BACwB;IACxB,QAAQ,CACN,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,sBAAsB,EAC9B,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAClC,6FAA6F;IAC7F,IAAI,CAAC,IAAI,EAAE,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;CACtH"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/search/source.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The search text rules, one owner: normalization, tokenization, the body scanner that keeps original
3
+ * byte offsets, query normalization and the automatic fallback's relaxation, plus the UTF-8 helpers
4
+ * excerpts need. Moved unchanged from portal-webmcp 0.3.1 (`search.ts`, `text.ts`).
5
+ */
6
+ export declare function utf8(value: string): Uint8Array;
7
+ export declare function utf8ByteLength(value: string): number;
8
+ /**
9
+ * Move an index forward until it starts a UTF-8 sequence. A slice that begins on
10
+ * a continuation byte would decode to a replacement character, so continuations
11
+ * are skipped rather than replaced.
12
+ */
13
+ export declare function forwardBoundary(bytes: Uint8Array, index: number): number;
14
+ /** Move an index backward until it ends a complete UTF-8 sequence. */
15
+ export declare function backwardBoundary(bytes: Uint8Array, index: number): number;
16
+ export declare function decodeUtf8(bytes: Uint8Array, start: number, end: number): string;
17
+ /** Collapse every maximal whitespace run to one ASCII space and trim both ends. */
18
+ export declare function collapseWhitespace(value: string): string;
19
+ /** Locale-independent normalization: Unicode NFKC then `toLowerCase()`. */
20
+ export declare function normalize(value: string): string;
21
+ /** Tokenization into maximal Unicode letter-or-number sequences of the normalized text. */
22
+ export declare function tokenize(value: string): string[];
23
+ /** A field's normalized phrase is its tokens joined by one ASCII space. */
24
+ export declare function phrase(value: string): string;
25
+ /**
26
+ * Visits every body token in document order with the original UTF-8 byte range of the run that
27
+ * produced it (every token of one run shares its range). `visit` returns `true` to stop the scan.
28
+ * The in-memory index and the excerpt both read the body through this one scanner, so a match's
29
+ * offsets are the same wherever they are computed.
30
+ */
31
+ export declare function scanBody(body: string, visit: (term: string, start: number, end: number) => boolean | void): void;
32
+ export interface NormalizedQueryV1 {
33
+ readonly phrase: string;
34
+ readonly terms: readonly string[];
35
+ }
36
+ /** Duplicate query tokens collapse after their first occurrence; the phrase is the remainder. */
37
+ export declare function normalizeQuery(query: string): NormalizedQueryV1;
38
+ export interface RelaxedQueryV1 {
39
+ readonly query: NormalizedQueryV1;
40
+ readonly ignoredTerms: readonly string[];
41
+ }
42
+ /**
43
+ * Removes fixed conversational terms for automatic any-term fallback. If that
44
+ * would remove the whole query, the original normalized query stays intact.
45
+ */
46
+ export declare function relaxQuery(query: NormalizedQueryV1): RelaxedQueryV1;
47
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/search/text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAE9C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAMD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD;AAMD,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,2FAA2F;AAC3F,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhD;AAED,2EAA2E;AAC3E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAsBD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,GAAG,IAAI,CA0BhH;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAS/D;AAYD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,cAAc,CAQnE"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The search text rules, one owner: normalization, tokenization, the body scanner that keeps original
3
+ * byte offsets, query normalization and the automatic fallback's relaxation, plus the UTF-8 helpers
4
+ * excerpts need. Moved unchanged from portal-webmcp 0.3.1 (`search.ts`, `text.ts`).
5
+ */
6
+ const encoder = new TextEncoder();
7
+ const decoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: false });
8
+ export function utf8(value) {
9
+ return encoder.encode(value);
10
+ }
11
+ export function utf8ByteLength(value) {
12
+ return encoder.encode(value).byteLength;
13
+ }
14
+ function continuation(byte) {
15
+ return byte !== undefined && (byte & 0b1100_0000) === 0b1000_0000;
16
+ }
17
+ /**
18
+ * Move an index forward until it starts a UTF-8 sequence. A slice that begins on
19
+ * a continuation byte would decode to a replacement character, so continuations
20
+ * are skipped rather than replaced.
21
+ */
22
+ export function forwardBoundary(bytes, index) {
23
+ let cursor = Math.max(0, Math.min(index, bytes.byteLength));
24
+ while (cursor < bytes.byteLength && continuation(bytes[cursor]))
25
+ cursor += 1;
26
+ return cursor;
27
+ }
28
+ /** Move an index backward until it ends a complete UTF-8 sequence. */
29
+ export function backwardBoundary(bytes, index) {
30
+ let cursor = Math.max(0, Math.min(index, bytes.byteLength));
31
+ while (cursor > 0 && continuation(bytes[cursor]))
32
+ cursor -= 1;
33
+ return cursor;
34
+ }
35
+ export function decodeUtf8(bytes, start, end) {
36
+ return decoder.decode(bytes.subarray(start, end));
37
+ }
38
+ /** Collapse every maximal whitespace run to one ASCII space and trim both ends. */
39
+ export function collapseWhitespace(value) {
40
+ return value.replace(/\s+/gu, " ").trim();
41
+ }
42
+ const TOKEN = /[\p{L}\p{N}]+/gu;
43
+ const LETTER_OR_NUMBER = /[\p{L}\p{N}]/u;
44
+ const MARK = /\p{M}/u;
45
+ /** Locale-independent normalization: Unicode NFKC then `toLowerCase()`. */
46
+ export function normalize(value) {
47
+ return value.normalize("NFKC").toLowerCase();
48
+ }
49
+ /** Tokenization into maximal Unicode letter-or-number sequences of the normalized text. */
50
+ export function tokenize(value) {
51
+ return [...normalize(value).matchAll(TOKEN)].map((match) => match[0]);
52
+ }
53
+ /** A field's normalized phrase is its tokens joined by one ASCII space. */
54
+ export function phrase(value) {
55
+ return tokenize(value).join(" ");
56
+ }
57
+ /**
58
+ * Whether an original character can belong to a token run.
59
+ *
60
+ * Body tokens must keep original byte offsets, so the body is segmented before
61
+ * normalization rather than after. A character joins a run when it is a letter
62
+ * or number, a combining mark (so a decomposed sequence composes inside its own
63
+ * run), or a compatibility character whose NFKC form contains a letter or
64
+ * number. NFKC never composes across a character outside that set, so run-wise
65
+ * tokenization yields the same terms as tokenizing the whole normalized field.
66
+ */
67
+ const runMembership = new Map();
68
+ function inTokenRun(character) {
69
+ const cached = runMembership.get(character);
70
+ if (cached !== undefined)
71
+ return cached;
72
+ const member = LETTER_OR_NUMBER.test(character) || MARK.test(character) || LETTER_OR_NUMBER.test(character.normalize("NFKC"));
73
+ runMembership.set(character, member);
74
+ return member;
75
+ }
76
+ /**
77
+ * Visits every body token in document order with the original UTF-8 byte range of the run that
78
+ * produced it (every token of one run shares its range). `visit` returns `true` to stop the scan.
79
+ * The in-memory index and the excerpt both read the body through this one scanner, so a match's
80
+ * offsets are the same wherever they are computed.
81
+ */
82
+ export function scanBody(body, visit) {
83
+ let byteOffset = 0;
84
+ let runStart = 0;
85
+ let run = "";
86
+ let stopped = false;
87
+ const flush = () => {
88
+ if (run.length === 0)
89
+ return;
90
+ for (const match of normalize(run).matchAll(TOKEN)) {
91
+ if (visit(match[0], runStart, byteOffset) === true) {
92
+ stopped = true;
93
+ break;
94
+ }
95
+ }
96
+ run = "";
97
+ };
98
+ for (const character of body) {
99
+ if (inTokenRun(character)) {
100
+ if (run.length === 0)
101
+ runStart = byteOffset;
102
+ run += character;
103
+ }
104
+ else {
105
+ flush();
106
+ if (stopped)
107
+ return;
108
+ }
109
+ byteOffset += utf8(character).byteLength;
110
+ }
111
+ flush();
112
+ }
113
+ /** Duplicate query tokens collapse after their first occurrence; the phrase is the remainder. */
114
+ export function normalizeQuery(query) {
115
+ const terms = [];
116
+ const seen = new Set();
117
+ for (const token of tokenize(query)) {
118
+ if (seen.has(token))
119
+ continue;
120
+ seen.add(token);
121
+ terms.push(token);
122
+ }
123
+ return { phrase: terms.join(" "), terms: Object.freeze(terms) };
124
+ }
125
+ // Fixed package text, deliberately not locale-sensitive. These words carry
126
+ // little retrieval signal in ordinary English questions. They are removed only
127
+ // by the automatic fallback, never by explicit `all` or `any` matching.
128
+ // prettier-ignore
129
+ const CONVERSATIONAL_TERMS = new Set([
130
+ "a", "an", "and", "are", "as", "at", "be", "by", "can", "did", "do", "does",
131
+ "for", "from", "how", "in", "is", "it", "of", "on", "or", "should", "that", "the",
132
+ "this", "to", "was", "what", "when", "where", "which", "who", "why", "will", "with",
133
+ ]);
134
+ /**
135
+ * Removes fixed conversational terms for automatic any-term fallback. If that
136
+ * would remove the whole query, the original normalized query stays intact.
137
+ */
138
+ export function relaxQuery(query) {
139
+ const terms = query.terms.filter((term) => !CONVERSATIONAL_TERMS.has(term));
140
+ if (terms.length === 0)
141
+ return { query, ignoredTerms: Object.freeze([]) };
142
+ const kept = new Set(terms);
143
+ return {
144
+ query: { phrase: terms.join(" "), terms: Object.freeze(terms) },
145
+ ignoredTerms: Object.freeze(query.terms.filter((term) => !kept.has(term))),
146
+ };
147
+ }
148
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/search/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The guarded transport a profile sees. It checks every URL and every redirect hop against the
3
+ * run's host set (the profile's hosts within the connector's credential hosts and keyless domains)
4
+ * and the address rule, reads and follows robots.txt for keyless hosts, applies the method rule and
5
+ * the header allowlist, follows redirects itself with the guard re-run per hop, counts the request
6
+ * budget, honours the deadline and maps statuses to outcomes. Any refusal or error status stops
7
+ * the run: the call throws and the stop is recorded here, so a profile cannot swallow it.
8
+ */
9
+ import { type Connector } from "../connectors.js";
10
+ import { type FetchIdentity } from "./robots.js";
11
+ import type { ProfileTransport, RequestRules, SourceBudget, SourceOutcome, SourceRequestRow, StatusRules, Transport } from "./types.js";
12
+ export declare const DEFAULT_SOURCE_BUDGET: Readonly<SourceBudget>;
13
+ /**
14
+ * The engine's status sets. 503 is not deferred: it ends `provider_unavailable` with a retry and
15
+ * any `retry_after`; a declaration's `errors` rows pass their own sets.
16
+ */
17
+ export declare const DEFAULT_STATUS_RULES: Readonly<StatusRules>;
18
+ /** Why a run stopped. */
19
+ export interface Stop {
20
+ outcome: SourceOutcome;
21
+ reason?: string;
22
+ detail?: string;
23
+ status?: number;
24
+ retry: boolean;
25
+ retry_after?: string;
26
+ }
27
+ /** Thrown through a profile when the run stops. */
28
+ export declare class SourceStop extends Error {
29
+ readonly stop: Stop;
30
+ constructor(stop: Stop);
31
+ }
32
+ export interface HostSet {
33
+ /** Every host a request may reach. */
34
+ allowed: ReadonlySet<string>;
35
+ /** Hosts a transport may send the credential to. */
36
+ credential: ReadonlySet<string>;
37
+ /** Keyless hosts: the robots.txt gate applies. */
38
+ keyless: ReadonlySet<string>;
39
+ }
40
+ /**
41
+ * The run's host set: the profile's hosts, each of which must be a credential host of the auth
42
+ * kind or a declared keyless domain. A host outside both is returned as undeclared.
43
+ */
44
+ export declare function sourceHostSet(connector: Pick<Connector, "auth" | "domains">, hosts: readonly string[]): {
45
+ ok: true;
46
+ hosts: HostSet;
47
+ } | {
48
+ ok: false;
49
+ undeclared: string[];
50
+ };
51
+ export interface GuardContext {
52
+ hosts: HostSet;
53
+ transport: Transport;
54
+ identity: FetchIdentity;
55
+ budget: SourceBudget;
56
+ rules: RequestRules;
57
+ statuses: StatusRules;
58
+ now: () => Date;
59
+ /**
60
+ * Whether a request may be conditional. A complete observation must read the whole listing, so
61
+ * it sends no validator and a not-modified answer stops it.
62
+ */
63
+ conditional: boolean;
64
+ signal?: AbortSignal;
65
+ /** Each request's own timeout. */
66
+ requestTimeoutMs?: number;
67
+ }
68
+ export interface GuardedTransport {
69
+ transport: ProfileTransport;
70
+ /** Every request, sent or refused, in order. */
71
+ requests: SourceRequestRow[];
72
+ /** The first stop, if any. */
73
+ stopped(): Stop | undefined;
74
+ /** Requests left in the run. */
75
+ remaining(): number;
76
+ /** End the run: every later request throws, from a reference the profile kept or not. */
77
+ close(): void;
78
+ }
79
+ /** `promise`, or a rejection once `signal` aborts; the abandoned promise's later failure is ignored. */
80
+ export declare function raceAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T>;
81
+ export declare function guardTransport(ctx: GuardContext): GuardedTransport;
82
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/source-engine/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,EAA8C,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,KAAK,EAIV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,SAAS,EAEV,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,YAAY,CAOvD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,WAAW,CAIrD,CAAC;AAmBH,yBAAyB;AACzB,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mDAAmD;AACnD,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;gBACR,IAAI,EAAE,IAAI;CAKvB;AAED,MAAM,WAAW,OAAO;IACtB,sCAAsC;IACtC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,oDAAoD;IACpD,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,kDAAkD;IAClD,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAc1K;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB;;;OAGG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,8BAA8B;IAC9B,OAAO,IAAI,IAAI,GAAG,SAAS,CAAC;IAC5B,gCAAgC;IAChC,SAAS,IAAI,MAAM,CAAC;IACpB,yFAAyF;IACzF,KAAK,IAAI,IAAI,CAAC;CACf;AAeD,wGAAwG;AACxG,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAa7F;AAoBD,wBAAgB,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,gBAAgB,CA2NlE"}