stitchkit 0.114.0 → 0.114.2

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 (94) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +1 -1
  3. package/dist/browser/client-url.d.ts.map +1 -1
  4. package/dist/entrypoints/agent-runtime/coding-tools.js +1 -1
  5. package/dist/entrypoints/agent-runtime/harness.js +4 -4
  6. package/dist/entrypoints/agent-runtime/realtime.js +2 -2
  7. package/dist/entrypoints/agent-runtime/sandbox.js +3 -3
  8. package/dist/entrypoints/agent-runtime/sqlite/bun.js +3 -3
  9. package/dist/entrypoints/agent-runtime/sqlite/node.js +3 -3
  10. package/dist/entrypoints/agent-runtime/testing.js +4 -4
  11. package/dist/entrypoints/agent-runtime.js +12 -12
  12. package/dist/entrypoints/application/directory-inbox.js +3 -3
  13. package/dist/entrypoints/application.js +4 -4
  14. package/dist/entrypoints/cli/publish.js +1 -1
  15. package/dist/entrypoints/cli.js +4 -4
  16. package/dist/entrypoints/contract.js +2 -2
  17. package/dist/entrypoints/http.js +2 -2
  18. package/dist/entrypoints/index.js +5 -5
  19. package/dist/entrypoints/node.js +3 -3
  20. package/dist/entrypoints/observability.js +3 -3
  21. package/dist/entrypoints/react/keyboard/testing.d.ts +2 -0
  22. package/dist/entrypoints/react/keyboard/testing.d.ts.map +1 -0
  23. package/dist/entrypoints/react/keyboard/testing.js +127 -0
  24. package/dist/entrypoints/react/keyboard.d.ts +4 -2
  25. package/dist/entrypoints/react/keyboard.d.ts.map +1 -1
  26. package/dist/entrypoints/react/keyboard.js +83 -319
  27. package/dist/entrypoints/react.js +15 -3
  28. package/dist/entrypoints/realtime.js +1 -1
  29. package/dist/entrypoints/remote.js +1 -1
  30. package/dist/entrypoints/server.js +18 -18
  31. package/dist/entrypoints/telegram/grammy.d.ts +2 -0
  32. package/dist/entrypoints/telegram/grammy.d.ts.map +1 -0
  33. package/dist/entrypoints/telegram/grammy.js +50 -0
  34. package/dist/entrypoints/telegram/screens.js +1 -1
  35. package/dist/entrypoints/telegram.js +16 -10
  36. package/dist/entrypoints/testing.js +3 -3
  37. package/dist/entrypoints/tools/connections.js +10 -10
  38. package/dist/entrypoints/tools.js +19 -19
  39. package/dist/entrypoints/tracking.js +1 -1
  40. package/dist/{index-hs35ss3p.js → index-61hve0ez.js} +4 -25
  41. package/dist/index-6j725ez5.js +25 -0
  42. package/dist/{index-1csp1hwm.js → index-6p3frkv5.js} +1 -1
  43. package/dist/{index-erv5shjq.js → index-912sza5h.js} +1 -1
  44. package/dist/{index-fy4av0hq.js → index-9bwcthxw.js} +1 -1
  45. package/dist/{index-523tq7y4.js → index-a3462dqf.js} +1 -1
  46. package/dist/{index-506kd458.js → index-aw6zahv1.js} +1 -1
  47. package/dist/{index-tpwbct8j.js → index-dc9ere5p.js} +1 -1
  48. package/dist/{index-cxpcdswt.js → index-mgb7r8b8.js} +123 -63
  49. package/dist/{index-7fc0c2np.js → index-n3v695sb.js} +1 -1
  50. package/dist/index-p02zgk8x.js +351 -0
  51. package/dist/{index-vtann8bz.js → index-p0rf7sq9.js} +8 -8
  52. package/dist/{index-aykhzcnf.js → index-qj1sy4ep.js} +1 -1
  53. package/dist/{index-k7z3j3hr.js → index-tnxsq7cw.js} +4 -4
  54. package/dist/{index-c5at3ykd.js → index-tsngj2b5.js} +22 -10
  55. package/dist/internal/pinned-http.d.ts +27 -0
  56. package/dist/internal/pinned-http.d.ts.map +1 -0
  57. package/dist/internal/secure-fetch.d.ts +26 -6
  58. package/dist/internal/secure-fetch.d.ts.map +1 -1
  59. package/dist/react/entity-cache.d.ts +24 -2
  60. package/dist/react/entity-cache.d.ts.map +1 -1
  61. package/dist/react/keyboard/hooks.d.ts +41 -10
  62. package/dist/react/keyboard/hooks.d.ts.map +1 -1
  63. package/dist/react/keyboard/layers.d.ts +27 -8
  64. package/dist/react/keyboard/layers.d.ts.map +1 -1
  65. package/dist/react/keyboard/modality.d.ts +21 -0
  66. package/dist/react/keyboard/modality.d.ts.map +1 -0
  67. package/dist/react/keyboard/refs.d.ts +13 -0
  68. package/dist/react/keyboard/refs.d.ts.map +1 -0
  69. package/dist/react/keyboard/testing.d.ts +80 -0
  70. package/dist/react/keyboard/testing.d.ts.map +1 -0
  71. package/dist/react/keyboard/zone.d.ts +60 -10
  72. package/dist/react/keyboard/zone.d.ts.map +1 -1
  73. package/dist/telegram/budget-transformer.d.ts +35 -0
  74. package/dist/telegram/budget-transformer.d.ts.map +1 -0
  75. package/dist/telegram/outbound-budget.d.ts +4 -2
  76. package/dist/telegram/outbound-budget.d.ts.map +1 -1
  77. package/llms/react-keyboard-testing.txt +24 -0
  78. package/llms/react-keyboard.txt +264 -4
  79. package/llms/react.txt +1 -1
  80. package/llms/server.3.txt +31 -0
  81. package/llms/stitchkit.2.txt +118 -0
  82. package/llms/stitchkit.txt +4 -118
  83. package/llms/telegram-grammy.txt +22 -0
  84. package/llms/telegram.txt +19 -7
  85. package/llms-full.txt +345 -12
  86. package/llms.txt +7 -5
  87. package/package.json +9 -1
  88. package/dist/{index-616xh7f2.js → index-4qnzda76.js} +0 -0
  89. package/dist/{index-fsw1ybf3.js → index-d9hq291n.js} +3 -3
  90. package/dist/{index-bjcjqj46.js → index-m8a44e64.js} +3 -3
  91. package/dist/{index-5efrpfmj.js → index-qndsr7f0.js} +3 -3
  92. package/dist/{index-zktz242w.js → index-s47ac8zt.js} +3 -3
  93. package/dist/{index-56yx8dxp.js → index-tvtacc9a.js} +3 -3
  94. /package/dist/{index-v1tswj0z.js → index-txg1npmg.js} +0 -0
@@ -0,0 +1,351 @@
1
+ // src/react/keyboard/layers.ts
2
+ var RANK = {
3
+ overlay: 4,
4
+ local: 3,
5
+ route: 2,
6
+ zone: 1,
7
+ global: 0
8
+ };
9
+ var KEY_FIELD_SELECTOR = [
10
+ "input:not([type=button],[type=submit],[type=reset],[type=checkbox],[type=image])",
11
+ "textarea",
12
+ "select",
13
+ "[contenteditable]:not([contenteditable=false])",
14
+ "[role=textbox]",
15
+ "[role=combobox]",
16
+ "[role=slider]",
17
+ "[role=spinbutton]",
18
+ "[data-local-keys]"
19
+ ].join(",");
20
+ function hasClosest(target) {
21
+ return typeof target === "object" && target !== null && "closest" in target && typeof target.closest === "function";
22
+ }
23
+ function closestFromTarget(target, selectors) {
24
+ return hasClosest(target) ? target.closest(selectors) : null;
25
+ }
26
+ function isKeyFieldTarget2(target) {
27
+ const field = closestFromTarget(target, KEY_FIELD_SELECTOR);
28
+ return field !== null && field !== undefined;
29
+ }
30
+ function liveScope(entry) {
31
+ const read = entry.state.scope;
32
+ if (read === undefined)
33
+ return "unscoped";
34
+ const element = read();
35
+ if (element === null || !element.isConnected)
36
+ return null;
37
+ const inert = element.closest("[inert]");
38
+ if (inert !== null && inert !== undefined)
39
+ return null;
40
+ if (element.checkVisibility !== undefined && !element.checkVisibility())
41
+ return null;
42
+ return element;
43
+ }
44
+ function askingOrder(entries) {
45
+ const live = [];
46
+ for (const entry of entries) {
47
+ if (entry.state.active === false)
48
+ continue;
49
+ const scope = liveScope(entry);
50
+ if (scope !== null)
51
+ live.push({ entry, scope, depth: 0 });
52
+ }
53
+ for (const layer of live) {
54
+ const own = layer.scope;
55
+ if (own === "unscoped")
56
+ continue;
57
+ layer.depth = live.filter((other) => other !== layer && other.entry.state.kind === layer.entry.state.kind && other.scope !== "unscoped" && other.scope !== own && other.scope.contains(own)).length;
58
+ }
59
+ return live.sort((left, right) => RANK[right.entry.state.kind] - RANK[left.entry.state.kind] || right.depth - left.depth || right.entry.order - left.entry.order);
60
+ }
61
+ function createKeyLayerStack2(target) {
62
+ const entries = new Set;
63
+ let activations = 0;
64
+ const bubbling = (event) => {
65
+ dispatch(event, "bubble");
66
+ };
67
+ const capturing = (event) => {
68
+ dispatch(event, "capture");
69
+ };
70
+ const attached = { bubble: false, capture: false };
71
+ const phaseOf = (state) => state.phase ?? "bubble";
72
+ function sync() {
73
+ for (const phase of ["bubble", "capture"]) {
74
+ const wanted = [...entries].some((entry) => phaseOf(entry.state) === phase);
75
+ if (wanted === attached[phase])
76
+ continue;
77
+ attached[phase] = wanted;
78
+ const listener = phase === "capture" ? capturing : bubbling;
79
+ if (wanted)
80
+ target.addEventListener("keydown", listener, phase === "capture");
81
+ else
82
+ target.removeEventListener("keydown", listener, phase === "capture");
83
+ }
84
+ }
85
+ function refuseUnlessLocal(state) {
86
+ if (phaseOf(state) === "capture" && state.kind !== "local") {
87
+ throw new Error(`A ${state.kind} layer cannot listen in the capture phase; only a local layer can`);
88
+ }
89
+ }
90
+ function dispatch(event, phase = "bubble") {
91
+ if (event.defaultPrevented || event.isComposing)
92
+ return false;
93
+ const isEscape = event.key === "Escape";
94
+ if (isEscape && event.repeat)
95
+ return false;
96
+ const inField = !isEscape && isKeyFieldTarget2(event.target);
97
+ let behindOverlay = false;
98
+ for (const { entry } of askingOrder(entries)) {
99
+ const { kind } = entry.state;
100
+ if (behindOverlay && kind !== "overlay")
101
+ break;
102
+ if (kind === "overlay")
103
+ behindOverlay = true;
104
+ if (phaseOf(entry.state) !== phase)
105
+ continue;
106
+ if (inField && entry.state.fields !== "include")
107
+ continue;
108
+ if (entry.state.onKey(event)) {
109
+ event.preventDefault();
110
+ if (phase === "capture")
111
+ event.stopPropagation?.();
112
+ return true;
113
+ }
114
+ }
115
+ return false;
116
+ }
117
+ function add(state) {
118
+ refuseUnlessLocal(state);
119
+ const entry = { state, order: ++activations };
120
+ entries.add(entry);
121
+ sync();
122
+ return {
123
+ update(next) {
124
+ refuseUnlessLocal(next);
125
+ const reactivated = entry.state.active === false && next.active !== false;
126
+ const moved = phaseOf(entry.state) !== phaseOf(next);
127
+ entry.state = next;
128
+ if (reactivated)
129
+ entry.order = ++activations;
130
+ if (moved)
131
+ sync();
132
+ },
133
+ remove() {
134
+ if (!entries.delete(entry))
135
+ return;
136
+ sync();
137
+ }
138
+ };
139
+ }
140
+ return { add, dispatch };
141
+ }
142
+
143
+ // src/react/keyboard/zone.ts
144
+ var ZONE_ATTRIBUTE = "data-keyboard-zone";
145
+ function nextZoneIndex2({
146
+ length,
147
+ index,
148
+ move,
149
+ loop
150
+ }) {
151
+ if (length <= 0)
152
+ return move === "previous" || move === "first" ? "before-start" : "after-end";
153
+ if (move === "first")
154
+ return 0;
155
+ if (move === "last")
156
+ return length - 1;
157
+ if (index < 0 || index >= length)
158
+ return move === "next" ? 0 : length - 1;
159
+ const target = move === "next" ? index + 1 : index - 1;
160
+ if (target >= 0 && target < length)
161
+ return target;
162
+ if (loop)
163
+ return target < 0 ? length - 1 : 0;
164
+ return target < 0 ? "before-start" : "after-end";
165
+ }
166
+ function zoneIntent(event, orientation) {
167
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
168
+ return null;
169
+ const vertical = orientation === "vertical";
170
+ switch (event.key) {
171
+ case (vertical ? "ArrowDown" : "ArrowRight"):
172
+ return { type: "move", move: "next" };
173
+ case (vertical ? "ArrowUp" : "ArrowLeft"):
174
+ return { type: "move", move: "previous" };
175
+ case (vertical ? "ArrowRight" : "ArrowDown"):
176
+ return { type: "enter" };
177
+ case (vertical ? "ArrowLeft" : "ArrowUp"):
178
+ return { type: "exit" };
179
+ case "Home":
180
+ return { type: "move", move: "first" };
181
+ case "End":
182
+ return { type: "move", move: "last" };
183
+ case "Enter":
184
+ return { type: "confirm" };
185
+ default:
186
+ return null;
187
+ }
188
+ }
189
+ function resolveZoneIndex(items, value, pointed) {
190
+ if (pointed !== null) {
191
+ const index = items.indexOf(pointed);
192
+ if (index >= 0)
193
+ return index;
194
+ }
195
+ if (value !== null) {
196
+ const index = items.indexOf(value);
197
+ if (index >= 0)
198
+ return index;
199
+ }
200
+ return items.length > 0 ? 0 : -1;
201
+ }
202
+ function isFieldInside(target, zone) {
203
+ const field = closestFromTarget(target, KEY_FIELD_SELECTOR);
204
+ if (field === null || field === undefined || field === zone)
205
+ return false;
206
+ return closestFromTarget(field, `[${ZONE_ATTRIBUTE}]`) === zone;
207
+ }
208
+ function createNavZone2(initial) {
209
+ let options = initial;
210
+ let pointed = null;
211
+ let awaiting = null;
212
+ const elements = new Map;
213
+ const listeners = new Set;
214
+ const point = (id) => {
215
+ if (pointed === id)
216
+ return;
217
+ pointed = id;
218
+ for (const listener of listeners)
219
+ listener();
220
+ };
221
+ const chosenValue = () => options.value ?? null;
222
+ function currentIndex() {
223
+ return resolveZoneIndex(options.items, chosenValue(), pointed);
224
+ }
225
+ function current() {
226
+ return options.items[currentIndex()] ?? null;
227
+ }
228
+ function focusElement(element) {
229
+ element.focus({ preventScroll: true });
230
+ element.scrollIntoView?.({ block: "nearest", inline: "nearest" });
231
+ }
232
+ function focus(id) {
233
+ const target = id ?? current();
234
+ if (target === null)
235
+ return false;
236
+ point(target);
237
+ const element = elements.get(target);
238
+ if (element === undefined) {
239
+ awaiting = target;
240
+ options.onReveal?.(target);
241
+ return true;
242
+ }
243
+ awaiting = null;
244
+ focusElement(element);
245
+ return true;
246
+ }
247
+ const taken = (answer) => answer !== false;
248
+ function choose(id, cause) {
249
+ if (options.mode !== "focus")
250
+ options.onChange(id, cause);
251
+ }
252
+ function apply(intent) {
253
+ const { items, mode = "select", loop = false } = options;
254
+ const index = currentIndex();
255
+ const id = items[index] ?? null;
256
+ switch (intent.type) {
257
+ case "move": {
258
+ const landed = nextZoneIndex2({ length: items.length, index, move: intent.move, loop });
259
+ if (typeof landed !== "number") {
260
+ if (options.onBoundary === undefined)
261
+ return false;
262
+ return taken(options.onBoundary(landed === "before-start" ? "start" : "end"));
263
+ }
264
+ const next = items[landed];
265
+ if (next === undefined)
266
+ return false;
267
+ focus(next);
268
+ if (mode === "select" && next !== chosenValue())
269
+ choose(next, "arrow");
270
+ return true;
271
+ }
272
+ case "enter":
273
+ return id !== null && options.onEnter !== undefined && taken(options.onEnter(id));
274
+ case "exit":
275
+ return options.onExit !== undefined && taken(options.onExit());
276
+ case "confirm":
277
+ if (id === null || mode === "focus")
278
+ return false;
279
+ if (mode === "highlight") {
280
+ choose(id, "confirm");
281
+ return true;
282
+ }
283
+ return options.onEnter !== undefined && taken(options.onEnter(id));
284
+ }
285
+ }
286
+ return {
287
+ update(next) {
288
+ const changed = (next.value ?? null) !== chosenValue();
289
+ options = next;
290
+ if (changed)
291
+ point(null);
292
+ },
293
+ get options() {
294
+ return options;
295
+ },
296
+ pointedItem: () => pointed,
297
+ current,
298
+ keyDown(event, zone) {
299
+ if (event.defaultPrevented || event.isComposing || isFieldInside(event.target, zone)) {
300
+ return false;
301
+ }
302
+ if (closestFromTarget(event.target, `[${ZONE_ATTRIBUTE}]`) !== zone)
303
+ return false;
304
+ const intent = zoneIntent(event, options.orientation ?? "vertical");
305
+ if (intent === null || options.ignore?.(event) === true)
306
+ return false;
307
+ const landsOnCurrent = event.target === zone && intent.type === "move" && (intent.move === "next" || intent.move === "previous");
308
+ if (!(landsOnCurrent ? focus() : apply(intent)))
309
+ return false;
310
+ event.preventDefault();
311
+ return true;
312
+ },
313
+ keyFromOutside(event) {
314
+ if (closestFromTarget(event.target, `[${ZONE_ATTRIBUTE}]`) !== null)
315
+ return false;
316
+ const intent = zoneIntent(event, options.orientation ?? "vertical");
317
+ if (intent?.type !== "move" || intent.move !== "next" && intent.move !== "previous") {
318
+ return false;
319
+ }
320
+ if (options.ignore?.(event) === true)
321
+ return false;
322
+ return options.outside === "move" ? apply(intent) : focus();
323
+ },
324
+ focused(id) {
325
+ if (id !== pointed && !options.items.includes(id))
326
+ return;
327
+ awaiting = null;
328
+ point(id);
329
+ },
330
+ focus,
331
+ setItemElement(id, element) {
332
+ if (element === null) {
333
+ elements.delete(id);
334
+ return;
335
+ }
336
+ elements.set(id, element);
337
+ if (id === awaiting) {
338
+ awaiting = null;
339
+ focusElement(element);
340
+ }
341
+ },
342
+ subscribe(listener) {
343
+ listeners.add(listener);
344
+ return () => {
345
+ listeners.delete(listener);
346
+ };
347
+ }
348
+ };
349
+ }
350
+
351
+ export { KEY_FIELD_SELECTOR, isKeyFieldTarget2, createKeyLayerStack2, ZONE_ATTRIBUTE, nextZoneIndex2, resolveZoneIndex, createNavZone2 };
@@ -27,14 +27,6 @@ import {
27
27
  bindContract,
28
28
  mediaTypeEssence
29
29
  } from "./index-cqmqyjax.js";
30
- import {
31
- readBoundedChunks,
32
- concatChunks,
33
- readBoundedBody2
34
- } from "./index-5efrpfmj.js";
35
- import {
36
- assertPositiveSafeInteger
37
- } from "./index-0s4xebbg.js";
38
30
  import {
39
31
  assertCorsConfig,
40
32
  isOriginAllowed,
@@ -59,6 +51,11 @@ import {
59
51
  getClientInfo2,
60
52
  parseQueryParams
61
53
  } from "./index-kw1ws0cs.js";
54
+ import {
55
+ readBoundedChunks,
56
+ concatChunks,
57
+ readBoundedBody2
58
+ } from "./index-qndsr7f0.js";
62
59
  import {
63
60
  abortReason,
64
61
  untilAborted
@@ -67,6 +64,9 @@ import {
67
64
  isUnsafeKey,
68
65
  safeJsonParse
69
66
  } from "./index-zsarb5xp.js";
67
+ import {
68
+ assertPositiveSafeInteger
69
+ } from "./index-0s4xebbg.js";
70
70
  import {
71
71
  AppError2,
72
72
  badRequest2,
@@ -19,7 +19,7 @@ import {
19
19
  appendEventIn,
20
20
  ArchiveProjectionSchema,
21
21
  createAgentRuntimeStore2
22
- } from "./index-523tq7y4.js";
22
+ } from "./index-a3462dqf.js";
23
23
  import {
24
24
  AgentConversationPageSchema2,
25
25
  AgentConversationMessagePageSchema2
@@ -23,19 +23,19 @@ import {
23
23
  createToolRunner,
24
24
  formatToolError
25
25
  } from "./index-htxh46ej.js";
26
+ import {
27
+ collectToolSurface
28
+ } from "./index-86nbfysb.js";
26
29
  import {
27
30
  fetchGuarded,
28
31
  readCapped
29
- } from "./index-cxpcdswt.js";
32
+ } from "./index-mgb7r8b8.js";
30
33
  import {
31
34
  isWithinDir2
32
35
  } from "./index-5cc6r990.js";
33
36
  import {
34
37
  sleep
35
38
  } from "./index-eemvahkc.js";
36
- import {
37
- collectToolSurface
38
- } from "./index-86nbfysb.js";
39
39
  import {
40
40
  isUnsafeKey,
41
41
  safeJsonParse
@@ -336,6 +336,8 @@ function escapeRegex(value) {
336
336
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
337
337
  }
338
338
  function decodePathSegment(value) {
339
+ if (!value.includes("%"))
340
+ return value;
339
341
  try {
340
342
  return decodeURIComponent(value);
341
343
  } catch {
@@ -356,28 +358,38 @@ function createClientRouteMatcher(endpoint, contractPrefix, config) {
356
358
  const wildcard = patternSegments.at(-1)?.startsWith("*") === true;
357
359
  const fixedCount = wildcard ? patternSegments.length - 1 : patternSegments.length;
358
360
  const markers = Object.values(markerByKey);
361
+ const segmentTests = patternSegments.slice(0, fixedCount).map((pattern) => compileSegmentTest(pattern, markers));
359
362
  return (pathname) => {
360
- const actualSegments = pathname.split("/").filter(Boolean).map(decodePathSegment);
363
+ const actualSegments = pathname.split("/").filter(Boolean);
361
364
  if (wildcard ? actualSegments.length < fixedCount : actualSegments.length !== fixedCount) {
362
365
  return false;
363
366
  }
364
367
  for (let index = 0;index < fixedCount; index += 1) {
365
- const pattern = patternSegments[index];
368
+ const test = segmentTests[index];
366
369
  const actual = actualSegments[index];
367
- if (!pattern || actual === undefined)
370
+ if (test === undefined || actual === undefined)
368
371
  return false;
369
- if (pattern.startsWith(":"))
370
- continue;
371
- let source = escapeRegex(pattern);
372
- for (const marker of markers) {
373
- source = source.replaceAll(escapeRegex(marker), "[^/]+");
374
- }
375
- if (!new RegExp(`^${source}$`).test(actual))
372
+ if (test !== null && !test(decodePathSegment(actual)))
376
373
  return false;
377
374
  }
378
375
  return true;
379
376
  };
380
377
  }
378
+ function compileSegmentTest(pattern, markers) {
379
+ if (pattern.startsWith(":"))
380
+ return null;
381
+ let source = escapeRegex(pattern);
382
+ let marked = false;
383
+ for (const marker of markers) {
384
+ const next = source.replaceAll(escapeRegex(marker), "[^/]+");
385
+ marked ||= next !== source;
386
+ source = next;
387
+ }
388
+ if (!marked)
389
+ return (actual) => actual === pattern;
390
+ const expression = new RegExp(`^${source}$`);
391
+ return (actual) => expression.test(actual);
392
+ }
381
393
  function extractParamNames(path) {
382
394
  const matches = path.match(/:(\w+)/g);
383
395
  const names = matches ? matches.map((match) => match.slice(1)) : [];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * One hop over a socket opened to the address the guard validated.
3
+ *
4
+ * The address is given, never looked up here: that is what makes a validated
5
+ * answer the one the connection uses. The `Host` header keeps the URL's host
6
+ * and, over TLS, the certificate is verified against it (`servername`), so a
7
+ * pinned connection is not a weaker one. The body is a Fetch stream over the
8
+ * socket, with backpressure and cancellation preserved.
9
+ */
10
+ import type { IncomingMessage } from 'node:http';
11
+ /** One hop, already resolved: open the connection to exactly `address`. */
12
+ export type PinnedTransport = (url: URL, resolved: {
13
+ address: string;
14
+ family: 4 | 6;
15
+ }, signal: AbortSignal | undefined) => Promise<Response>;
16
+ /**
17
+ * One hop over a socket opened to `resolved.address`: the `Host` header keeps
18
+ * the URL's host and, for TLS, the certificate is verified against it
19
+ * (`servername`), so a pinned connection is not a weaker connection.
20
+ */
21
+ export declare function requestPinned(url: URL, resolved: {
22
+ address: string;
23
+ family: 4 | 6;
24
+ }, signal: AbortSignal | undefined, headers?: Record<string, string>): Promise<Response>;
25
+ /** An `IncomingMessage` as a streaming Fetch response, keeping backpressure and cancellation. */
26
+ export declare function pinnedResponse(incoming: IncomingMessage): Response;
27
+ //# sourceMappingURL=pinned-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-http.d.ts","sourceRoot":"","sources":["../../src/internal/pinned-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAIjD,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG,CAC5B,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE,EAC5C,MAAM,EAAE,WAAW,GAAG,SAAS,KAC5B,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE,EAC5C,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACnC,OAAO,CAAC,QAAQ,CAAC,CAgCnB;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,QAAQ,CA6ClE"}
@@ -1,3 +1,4 @@
1
+ import type { PinnedTransport } from './pinned-http.js';
1
2
  /** True unless the literal belongs to the globally routable unicast Internet. */
2
3
  export declare function isPrivateIp(ip: string): boolean;
3
4
  /**
@@ -14,13 +15,21 @@ export declare function assertPublicUrl(url: URL, signal?: AbortSignal): Promise
14
15
  /**
15
16
  * Fetch a URL with the SSRF guard enforced on the initial URL and on every
16
17
  * redirect hop — a public host can otherwise `302` to an internal address or a
17
- * non-http(s) scheme.
18
- *
19
- * Note: the DNS resolution here and the resolution `fetch` performs are
20
- * separate, so a hostile resolver retains a narrow rebinding window. The
21
- * per-hop re-check is the larger and fully-closed hole; a static private DNS
22
- * record is rejected outright.
18
+ * non-http(s) scheme — and with the connection pinned to the address that
19
+ * passed the check, so a resolver cannot answer public and then connect
20
+ * somewhere private.
21
+ */
22
+ /**
23
+ * The resolver seam: one `lookup` call per hop. Production uses `node:dns`;
24
+ * a test supplies a controlled answer to prove which address the socket went
25
+ * to, and that a second answer cannot open another one.
23
26
  */
27
+ export type GuardedDnsLookup = (host: string, options: {
28
+ all: true;
29
+ }) => Promise<Array<{
30
+ address: string;
31
+ family: number;
32
+ }>>;
24
33
  export interface GuardedFetchOptions {
25
34
  /**
26
35
  * Deadline for producing the FINAL response headers — DNS, connects and every
@@ -36,6 +45,17 @@ export interface GuardedFetchOptions {
36
45
  bodyTimeoutMs?: number;
37
46
  /** Optional caller cancellation, combined with both deadlines. */
38
47
  signal?: AbortSignal;
48
+ /**
49
+ * Test seam: the resolver whose answer the connection is pinned to. Default
50
+ * `node:dns`. It replaces the name lookup, never the address check.
51
+ */
52
+ dns?: GuardedDnsLookup;
53
+ /**
54
+ * Test seam: how one resolved hop is opened. Default the pinned
55
+ * `http`/`https` request. Only the redirect tests replace it; production and
56
+ * the rebinding test use the default, which is where pinning happens.
57
+ */
58
+ transport?: PinnedTransport;
39
59
  }
40
60
  export declare function fetchGuarded(start: URL, allowPrivate: boolean, options?: GuardedFetchOptions): Promise<Response>;
41
61
  export interface PinnedDocumentFetchOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"secure-fetch.d.ts","sourceRoot":"","sources":["../../src/internal/secure-fetch.ts"],"names":[],"mappings":"AAmEA,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA8D/C;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,GAAG,EACV,YAAY,EAAE,OAAO,EACrB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,QAAQ,CAAC,CAiDnB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;CACV;AAED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,2BAA2B;CACzC;AA8CD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CAkFjC;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnF"}
1
+ {"version":3,"file":"secure-fetch.d.ts","sourceRoot":"","sources":["../../src/internal/secure-fetch.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAmDrD,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA8D/C;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF;AAED;;;;;;GAMG;AACH;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,GAAG,EAAE,IAAI,CAAA;CAAE,KACnB,OAAO,CAAC,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAAC;AAQzD,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,GAAG,EACV,YAAY,EAAE,OAAO,EACrB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,QAAQ,CAAC,CAuDnB;AAqBD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;CACV;AAED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,2BAA2B;CACzC;AA+CD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,sBAAsB,CAAC,CA2CjC;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnF"}
@@ -47,7 +47,16 @@ export interface EntityCacheTotalPolicy<TData> {
47
47
  /** What to do when an unseen id makes the delta unknowable. Default `preserve`. */
48
48
  unknown?: 'preserve' | 'invalidate';
49
49
  }
50
- /** List envelope, scoped key and explicit CRUD policies. */
50
+ /**
51
+ * List envelope, scoped key and explicit CRUD policies. It stays an interface,
52
+ * not a union of shapes: a consumer's config is often a value of this type, and
53
+ * a union turns `compare` and `insertCompare` into a discriminated choice the
54
+ * compiler cannot narrow from the fields alone.
55
+ *
56
+ * At most one of `compare` and `insertCompare` is set — a list has one answer to
57
+ * "what order is this?". `createEntityCacheHandlers` refuses both at creation.
58
+ * With neither, a create goes to the `createAt` edge and every other row stays.
59
+ */
51
60
  export interface EntityCacheListConfig<TData, TListItem> {
52
61
  /** Static query-key prefix or an event-aware scoped key factory. */
53
62
  key: EntityCacheKey<TData>;
@@ -55,8 +64,21 @@ export interface EntityCacheListConfig<TData, TListItem> {
55
64
  createAt: 'start' | 'end';
56
65
  /** Explicit behavior when an update's id is absent from every cached page. */
57
66
  updateMissing: 'skip' | 'insert';
58
- /** Backend-equivalent ordering for each affected logical item array. */
67
+ /**
68
+ * Backend-equivalent ordering of each affected logical item array: it is
69
+ * sorted again after every create and update. Only for an order the row
70
+ * itself determines; never together with `insertCompare`.
71
+ */
59
72
  compare?: (left: TListItem, right: TListItem) => number;
73
+ /**
74
+ * Where a row that is *entering* the list goes: before the first row it sorts
75
+ * ahead of, with ties broken by `createAt` (`'start'`: before equal rows,
76
+ * `'end'`: after them). On a list already in this order the result is the one
77
+ * `compare` gives; on a list that is not — an order the server decides with
78
+ * facts the row does not carry — no other row moves, and a row that is already
79
+ * there is replaced in place. Never together with `compare`.
80
+ */
81
+ insertCompare?: (incoming: TListItem, existing: TListItem) => number;
60
82
  /** Cached data envelope; no runtime shape inference is performed. */
61
83
  shape: EntityCacheListShape;
62
84
  /** Optional per-query filter membership. Omit for the envelope-preserving legacy path. */
@@ -1 +1 @@
1
- {"version":3,"file":"entity-cache.d.ts","sourceRoot":"","sources":["../../src/react/entity-cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"entity-cache.d.ts","sourceRoot":"","sources":["../../src/react/entity-cache.ts"],"names":[],"mappings":"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"}