stitchkit 0.103.13 → 0.104.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/darwin-native.cjs +1 -3
  3. package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
  4. package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
  5. package/dist/application/directory-inbox-accept.d.ts +13 -0
  6. package/dist/application/directory-inbox-accept.d.ts.map +1 -0
  7. package/dist/application/directory-inbox-contract.d.ts +42 -5
  8. package/dist/application/directory-inbox-contract.d.ts.map +1 -1
  9. package/dist/application/directory-inbox-delivery.d.ts +14 -0
  10. package/dist/application/directory-inbox-delivery.d.ts.map +1 -0
  11. package/dist/application/directory-inbox-files.d.ts +28 -0
  12. package/dist/application/directory-inbox-files.d.ts.map +1 -0
  13. package/dist/application/directory-inbox-state.d.ts +14 -0
  14. package/dist/application/directory-inbox-state.d.ts.map +1 -0
  15. package/dist/application/directory-inbox.d.ts +2 -1
  16. package/dist/application/directory-inbox.d.ts.map +1 -1
  17. package/dist/application/file-state-store.d.ts +2 -8
  18. package/dist/application/file-state-store.d.ts.map +1 -1
  19. package/dist/application/state-store.d.ts +6 -1
  20. package/dist/application/state-store.d.ts.map +1 -1
  21. package/dist/browser/client-arguments.d.ts +4 -0
  22. package/dist/browser/client-arguments.d.ts.map +1 -0
  23. package/dist/browser/client-executors.d.ts.map +1 -1
  24. package/dist/browser/client.d.ts.map +1 -1
  25. package/dist/browser/contract-stream.d.ts.map +1 -1
  26. package/dist/browser/http.d.ts +2 -1
  27. package/dist/browser/http.d.ts.map +1 -1
  28. package/dist/browser/native-fetch.d.ts +8 -0
  29. package/dist/browser/native-fetch.d.ts.map +1 -0
  30. package/dist/contract/errors.d.ts +16 -12
  31. package/dist/contract/errors.d.ts.map +1 -1
  32. package/dist/contract/normalize.d.ts +5 -1
  33. package/dist/contract/normalize.d.ts.map +1 -1
  34. package/dist/contract/stream.d.ts +1 -0
  35. package/dist/contract/stream.d.ts.map +1 -1
  36. package/dist/entrypoints/agent-runtime/browser.js +3 -3
  37. package/dist/entrypoints/agent-runtime/coding-tools.js +6 -6
  38. package/dist/entrypoints/agent-runtime/harness-tools.js +8 -8
  39. package/dist/entrypoints/agent-runtime/harness.js +11 -11
  40. package/dist/entrypoints/agent-runtime/realtime.js +3 -3
  41. package/dist/entrypoints/agent-runtime/sandbox.js +6 -6
  42. package/dist/entrypoints/agent-runtime.js +13 -13
  43. package/dist/entrypoints/application/diagnostic-journal.js +1 -1
  44. package/dist/entrypoints/application/directory-inbox.js +424 -119
  45. package/dist/entrypoints/application/grammy.js +1 -1
  46. package/dist/entrypoints/application.d.ts +2 -2
  47. package/dist/entrypoints/application.d.ts.map +1 -1
  48. package/dist/entrypoints/application.js +7 -3
  49. package/dist/entrypoints/cli.d.ts +2 -0
  50. package/dist/entrypoints/cli.d.ts.map +1 -1
  51. package/dist/entrypoints/cli.js +757 -136
  52. package/dist/entrypoints/contract.js +3 -3
  53. package/dist/entrypoints/files/packaging.d.ts +3 -0
  54. package/dist/entrypoints/files/packaging.d.ts.map +1 -0
  55. package/dist/entrypoints/files/packaging.js +133 -0
  56. package/dist/entrypoints/files.js +10 -107
  57. package/dist/entrypoints/index.js +7 -7
  58. package/dist/entrypoints/node.js +8 -8
  59. package/dist/entrypoints/observability.js +2 -2
  60. package/dist/entrypoints/react.js +1 -1
  61. package/dist/entrypoints/remote.js +19 -6
  62. package/dist/entrypoints/server.d.ts +1 -1
  63. package/dist/entrypoints/server.d.ts.map +1 -1
  64. package/dist/entrypoints/server.js +23 -17
  65. package/dist/entrypoints/telegram.d.ts +1 -0
  66. package/dist/entrypoints/telegram.d.ts.map +1 -1
  67. package/dist/entrypoints/telegram.js +214 -98
  68. package/dist/entrypoints/testing.js +7 -7
  69. package/dist/entrypoints/tools/connections.d.ts +2 -2
  70. package/dist/entrypoints/tools/connections.d.ts.map +1 -1
  71. package/dist/entrypoints/tools/connections.js +427 -294
  72. package/dist/entrypoints/tools/invoker.js +6 -6
  73. package/dist/entrypoints/tools/mcp.d.ts +12 -0
  74. package/dist/entrypoints/tools/mcp.d.ts.map +1 -0
  75. package/dist/entrypoints/tools/mcp.js +45 -0
  76. package/dist/entrypoints/tools.d.ts +1 -0
  77. package/dist/entrypoints/tools.d.ts.map +1 -1
  78. package/dist/entrypoints/tools.js +82 -1147
  79. package/dist/entrypoints/tracking.js +1 -1
  80. package/dist/files/boundary.d.ts +2 -8
  81. package/dist/files/boundary.d.ts.map +1 -1
  82. package/dist/files/file-io.d.ts +0 -5
  83. package/dist/files/file-io.d.ts.map +1 -1
  84. package/dist/files/native-packaging-layout.d.ts +12 -0
  85. package/dist/files/native-packaging-layout.d.ts.map +1 -0
  86. package/dist/files/native-packaging.d.ts +72 -0
  87. package/dist/files/native-packaging.d.ts.map +1 -0
  88. package/dist/files/read.d.ts +2 -2
  89. package/dist/files/read.d.ts.map +1 -1
  90. package/dist/index-1a6jtnd9.js +88 -0
  91. package/dist/index-269zqj8m.js +77 -0
  92. package/dist/{index-r34mvse1.js → index-27a2pj09.js} +1 -1
  93. package/dist/{index-r956rndn.js → index-2hyavjjj.js} +3 -3
  94. package/dist/{index-m2xqkv55.js → index-2vnh05w4.js} +83 -14
  95. package/dist/{index-pw99k9h5.js → index-43p08g7t.js} +1 -1
  96. package/dist/{index-xwq9j1sf.js → index-4e0ah203.js} +9 -7
  97. package/dist/{index-qapzv4p5.js → index-5z6jn897.js} +1 -1
  98. package/dist/{index-ahvsksw5.js → index-6d9xaxw1.js} +1 -1
  99. package/dist/{index-8zfsgar0.js → index-6drst9sg.js} +11 -5
  100. package/dist/{index-x87j7csh.js → index-77nxk6ay.js} +2 -2
  101. package/dist/{index-dnn9z96q.js → index-a0zzh8ak.js} +3 -3
  102. package/dist/{index-kmpzj1cq.js → index-a3wma1hk.js} +1 -1
  103. package/dist/{index-j8aw2c0e.js → index-bakgedh8.js} +35 -7
  104. package/dist/index-bhb950qs.js +1145 -0
  105. package/dist/{index-tgzhq07n.js → index-cvda079a.js} +1 -1
  106. package/dist/{index-n2gre124.js → index-fa4wg312.js} +4 -4
  107. package/dist/{index-zp4jpkp0.js → index-fk18k56k.js} +2 -2
  108. package/dist/{index-afjvjyck.js → index-g2j7pnak.js} +2 -134
  109. package/dist/index-g95fk660.js +116 -0
  110. package/dist/{index-r5c4fedv.js → index-h2fhjqy7.js} +2 -1
  111. package/dist/{index-sybedc8b.js → index-hbd32c6a.js} +23 -94
  112. package/dist/{index-fyphpknh.js → index-hp9d77wk.js} +1 -1
  113. package/dist/index-jd470k6q.js +109 -0
  114. package/dist/{index-b2bz0kdm.js → index-kb8styz3.js} +4 -3
  115. package/dist/{index-0c419yx7.js → index-kemm0ej5.js} +12 -9
  116. package/dist/{index-db2spkv1.js → index-ptn0g0gj.js} +3 -3
  117. package/dist/{index-w575evhq.js → index-r4r70zmh.js} +1 -1
  118. package/dist/{index-12m2v2a9.js → index-s4evrmp5.js} +1 -1
  119. package/dist/{index-1khy8y7n.js → index-t1sr4aks.js} +3 -3
  120. package/dist/{index-45tdvqa3.js → index-wh0ecvyk.js} +1 -1
  121. package/dist/{index-n53mswt3.js → index-x928baz2.js} +8 -1
  122. package/dist/index-yk4g8805.js +133 -0
  123. package/dist/{index-ygkka6zn.js → index-ywppsaby.js} +28 -5
  124. package/dist/{index-9853ymwb.js → index-za6j7nwy.js} +18 -4
  125. package/dist/internal/bounded-file-read.d.ts +41 -0
  126. package/dist/internal/bounded-file-read.d.ts.map +1 -0
  127. package/dist/internal/exclusive-lock.d.ts +2 -0
  128. package/dist/internal/exclusive-lock.d.ts.map +1 -1
  129. package/dist/internal/with-exclusive-lock.d.ts +4 -2
  130. package/dist/internal/with-exclusive-lock.d.ts.map +1 -1
  131. package/dist/telegram/broadcast-delivery.d.ts +23 -0
  132. package/dist/telegram/broadcast-delivery.d.ts.map +1 -0
  133. package/dist/telegram/broadcast-failure.d.ts +22 -0
  134. package/dist/telegram/broadcast-failure.d.ts.map +1 -0
  135. package/dist/telegram/broadcast-state.d.ts +6 -3
  136. package/dist/telegram/broadcast-state.d.ts.map +1 -1
  137. package/dist/telegram/broadcast.d.ts +10 -5
  138. package/dist/telegram/broadcast.d.ts.map +1 -1
  139. package/dist/tools/cli/format.d.ts.map +1 -1
  140. package/dist/tools/cli/invoke.d.ts +2 -2
  141. package/dist/tools/cli/invoke.d.ts.map +1 -1
  142. package/dist/tools/cli/publication-assets.d.ts +10 -0
  143. package/dist/tools/cli/publication-assets.d.ts.map +1 -0
  144. package/dist/tools/cli/publication-contract.d.ts +75 -0
  145. package/dist/tools/cli/publication-contract.d.ts.map +1 -0
  146. package/dist/tools/cli/publication-control.d.ts +4 -0
  147. package/dist/tools/cli/publication-control.d.ts.map +1 -0
  148. package/dist/tools/cli/publication-storage.d.ts +32 -0
  149. package/dist/tools/cli/publication-storage.d.ts.map +1 -0
  150. package/dist/tools/cli/publication.d.ts +35 -0
  151. package/dist/tools/cli/publication.d.ts.map +1 -0
  152. package/dist/tools/cli/update.d.ts.map +1 -1
  153. package/dist/tools/connections/define.d.ts.map +1 -1
  154. package/dist/tools/connections/error-projection.d.ts +4 -0
  155. package/dist/tools/connections/error-projection.d.ts.map +1 -0
  156. package/dist/tools/connections/errors.d.ts +24 -8
  157. package/dist/tools/connections/errors.d.ts.map +1 -1
  158. package/dist/tools/connections/limits.d.ts +11 -31
  159. package/dist/tools/connections/limits.d.ts.map +1 -1
  160. package/dist/tools/connections/mcp-client.d.ts +6 -4
  161. package/dist/tools/connections/mcp-client.d.ts.map +1 -1
  162. package/dist/tools/connections/mcp.d.ts.map +1 -1
  163. package/dist/tools/connections/openapi.d.ts.map +1 -1
  164. package/dist/tools/connections/operation-limits.d.ts +25 -0
  165. package/dist/tools/connections/operation-limits.d.ts.map +1 -0
  166. package/dist/tools/connections/sse-frames.d.ts +11 -2
  167. package/dist/tools/connections/sse-frames.d.ts.map +1 -1
  168. package/dist/tools/connections/sse-session.d.ts +15 -2
  169. package/dist/tools/connections/sse-session.d.ts.map +1 -1
  170. package/dist/tools/connections/types.d.ts +19 -1
  171. package/dist/tools/connections/types.d.ts.map +1 -1
  172. package/dist/tools/execute-result.d.ts.map +1 -1
  173. package/dist/tools/execute.d.ts.map +1 -1
  174. package/dist/tools/internal/observe-hook.d.ts +3 -0
  175. package/dist/tools/internal/observe-hook.d.ts.map +1 -0
  176. package/dist/tools/internal/surface-projector.d.ts +2 -1
  177. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  178. package/dist/tools/mcp/mount.d.ts +2 -2
  179. package/dist/tools/mcp/mount.d.ts.map +1 -1
  180. package/dist/tools/mcp/prepare.d.ts +4 -5
  181. package/dist/tools/mcp/prepare.d.ts.map +1 -1
  182. package/dist/tools/mcp/register.d.ts +4 -1
  183. package/dist/tools/mcp/register.d.ts.map +1 -1
  184. package/dist/tools/mcp/runtime-tools.d.ts.map +1 -1
  185. package/dist/tools/remote.d.ts.map +1 -1
  186. package/dist/tools/runtime-tool-execution.d.ts +65 -0
  187. package/dist/tools/runtime-tool-execution.d.ts.map +1 -0
  188. package/dist/tools/runtime-tool-mcp.d.ts +27 -0
  189. package/dist/tools/runtime-tool-mcp.d.ts.map +1 -0
  190. package/dist/tools/runtime-tool.d.ts +9 -60
  191. package/dist/tools/runtime-tool.d.ts.map +1 -1
  192. package/dist/tools/surface.d.ts +12 -14
  193. package/dist/tools/surface.d.ts.map +1 -1
  194. package/llms/application.2.txt +221 -44
  195. package/llms/application.3.txt +3 -1
  196. package/llms/application.txt +1 -1
  197. package/llms/cli.2.txt +144 -1
  198. package/llms/cli.txt +123 -104
  199. package/llms/contract.txt +1 -1
  200. package/llms/files-packaging.txt +27 -0
  201. package/llms/process.txt +63 -1
  202. package/llms/server.4.txt +4 -1
  203. package/llms/server.5.txt +1 -0
  204. package/llms/stitchkit.2.txt +14 -0
  205. package/llms/stitchkit.txt +6 -4
  206. package/llms/telegram.txt +64 -2
  207. package/llms/tools-connections.txt +3 -0
  208. package/llms/tools-mcp.txt +29 -0
  209. package/llms/tools.2.txt +59 -0
  210. package/llms/tools.3.txt +1 -0
  211. package/llms/tools.txt +11 -52
  212. package/llms/upgrading-0.37.0-0.44.0.txt +444 -0
  213. package/llms/{upgrading-0.44.0-0.60.0.txt → upgrading-0.44.0-0.61.0.txt} +140 -271
  214. package/llms/{upgrading-0.61.0-0.74.0.txt → upgrading-0.62.0-0.80.0.txt} +217 -140
  215. package/llms/{upgrading-0.75.0-0.103.0.txt → upgrading-0.81.0-0.104.0.txt} +154 -217
  216. package/llms/upgrading.txt +4 -4
  217. package/llms-full.txt +745 -60
  218. package/llms.txt +14 -12
  219. package/native-assets.json +8 -0
  220. package/package.json +12 -3
  221. package/dist/index-wykebpn9.js +0 -221
  222. package/llms/upgrading-0.37.0.txt +0 -176
  223. package/dist/{index-69nvze1q.js → index-pptyv13k.js} +3 -3
@@ -1,159 +1,448 @@
1
1
  import {
2
- backoffDelay
3
- } from "../../index-g6a3na27.js";
4
- import {
2
+ DirectoryInboxIdentitySchema2,
5
3
  DirectoryInboxStateSchema2,
6
4
  emptyDirectoryInboxState,
7
5
  withRejection,
8
6
  claimEntry,
9
7
  completeEntry,
10
8
  releaseEntry,
9
+ ownsClaim,
10
+ renewEntry,
11
11
  forgetMissing
12
- } from "../../index-j8aw2c0e.js";
12
+ } from "../../index-bakgedh8.js";
13
+ import {
14
+ backoffDelay
15
+ } from "../../index-g6a3na27.js";
16
+ import"../../index-za6j7nwy.js";
17
+ import"../../index-5csmzesf.js";
18
+ import"../../index-v5ee8ath.js";
13
19
  import {
14
20
  defineManagedResource2
15
21
  } from "../../index-50ejfz75.js";
16
22
  import {
17
23
  createFileStateStore2
18
- } from "../../index-wykebpn9.js";
24
+ } from "../../index-269zqj8m.js";
25
+ import"../../index-g95fk660.js";
26
+ import {
27
+ writeAtomicFileData
28
+ } from "../../index-s4evrmp5.js";
29
+ import {
30
+ BoundedFileReadError,
31
+ readBoundedFile
32
+ } from "../../index-jd470k6q.js";
33
+ import {
34
+ publishAtomicFile
35
+ } from "../../index-8a9ksm91.js";
36
+ import {
37
+ raceAbort
38
+ } from "../../index-mbnnw3f2.js";
39
+ import {
40
+ isJsonData
41
+ } from "../../index-fm1c1a08.js";
19
42
 
20
43
  // src/application/directory-inbox.ts
21
- import { mkdir, readdir, readFile, rename, stat, unlink } from "node:fs/promises";
44
+ import { mkdir as mkdir2 } from "node:fs/promises";
45
+ import { join as join2 } from "node:path";
46
+ import { z as z2 } from "zod";
47
+
48
+ // src/application/directory-inbox-files.ts
49
+ import { createHash } from "node:crypto";
50
+ import { lstat, mkdir, open, opendir, unlink } from "node:fs/promises";
22
51
  import { join } from "node:path";
23
52
  import { z } from "zod";
24
- var REJECTED = "rejected";
25
53
  var ENTRY_NAME = /^[^.].*\.json$/;
26
- var RETRY_BACKOFF = { minDelayMs: 1000, maxDelayMs: 300000, jitter: 0 };
27
- var absent = (error) => error instanceof Error && ("code" in error) && error.code === "ENOENT";
28
- async function quietly(run) {
29
- try {
30
- await run();
31
- } catch (error) {
32
- if (!absent(error))
33
- throw error;
34
- }
54
+ var ACCEPTED_NAME = /^intake-[0-9a-f]{64}\.json$/;
55
+ var EnvelopeSchema = z.object({
56
+ schemaVersion: z.literal(1),
57
+ identity: DirectoryInboxIdentitySchema2,
58
+ entry: z.unknown()
59
+ }).strict();
60
+ var missingInboxFile = (error) => error instanceof Error && ("code" in error) && error.code === "ENOENT";
61
+ function inboxFilename(identity) {
62
+ return "intake-" + createHash("sha256").update(JSON.stringify([identity.source, identity.key])).digest("hex") + ".json";
35
63
  }
36
- function resolveLimits(config) {
37
- const integer = z.number().int();
64
+ function sameInboxIdentity(a, b) {
65
+ return a?.source === b.source && a.key === b.key;
66
+ }
67
+ function encodeInboxEntry(identity, entry, schema, maxBytes) {
68
+ const envelope = { schemaVersion: 1, identity, entry: schema.parse(entry) };
69
+ const snapshot = {};
70
+ if (!isJsonData(envelope, { maxDepth: 100, maxNodes: maxBytes, maxBytes, omitObjectUndefined: false }, snapshot))
71
+ throw new TypeError("Inbox entry must be lossless JSON within maxEntryBytes");
72
+ const encoded = JSON.stringify(snapshot.value);
73
+ if (encoded === undefined || new TextEncoder().encode(encoded).byteLength > maxBytes)
74
+ throw new RangeError("Inbox entry exceeds maxEntryBytes");
75
+ return encoded;
76
+ }
77
+ async function createInboxFiles(directory, maxBytes) {
78
+ const read = (name) => readBoundedFile(join(directory, name), maxBytes, {
79
+ rejectSymlinks: true,
80
+ singleLink: true,
81
+ stable: true
82
+ });
83
+ const matches = async (key, observation) => {
84
+ if (!observation)
85
+ return true;
86
+ try {
87
+ const current = await lstat(join(directory, key));
88
+ return current.isFile() && current.nlink === 1 && current.dev === observation.dev && current.ino === observation.ino && current.size === observation.size && current.mtimeMs === observation.mtimeMs && current.ctimeMs === observation.ctimeMs;
89
+ } catch (error) {
90
+ if (missingInboxFile(error))
91
+ return false;
92
+ throw error;
93
+ }
94
+ };
38
95
  return {
39
- pollIntervalMs: integer.min(10).parse(config.pollIntervalMs ?? 1000),
40
- leaseMs: integer.min(100).parse(config.leaseMs ?? 300000),
41
- maxAttempts: integer.min(1).max(1e4).parse(config.maxAttempts ?? 20),
42
- maxEntryBytes: integer.min(1).parse(config.maxEntryBytes ?? 1024 * 1024),
43
- retain: integer.min(1).max(1e5).parse(config.retain ?? 1000)
96
+ async names(limit) {
97
+ const names = [];
98
+ for await (const entry of await opendir(directory)) {
99
+ if (!entry.isFile() || !ENTRY_NAME.test(entry.name))
100
+ continue;
101
+ names.push(entry.name);
102
+ if (limit !== undefined && names.length >= limit)
103
+ break;
104
+ }
105
+ return names.sort();
106
+ },
107
+ async read(key, schema) {
108
+ try {
109
+ const source = await read(key);
110
+ if (!source.observation)
111
+ throw new Error("Inbox reader did not provide file observation");
112
+ let json;
113
+ try {
114
+ json = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(source.bytes));
115
+ } catch (error) {
116
+ return {
117
+ reason: "invalid",
118
+ detail: String(error).slice(0, 1000),
119
+ observation: source.observation
120
+ };
121
+ }
122
+ let identity;
123
+ if (ACCEPTED_NAME.test(key)) {
124
+ const envelope = EnvelopeSchema.safeParse(json);
125
+ if (!envelope.success || inboxFilename(envelope.data.identity) !== key)
126
+ return {
127
+ reason: "invalid",
128
+ detail: "Invalid programmatic inbox envelope",
129
+ observation: source.observation
130
+ };
131
+ identity = envelope.data.identity;
132
+ json = envelope.data.entry;
133
+ }
134
+ const parsed = schema.safeParse(json);
135
+ return parsed.success ? {
136
+ entry: parsed.data,
137
+ observation: source.observation,
138
+ ...identity && { identity }
139
+ } : {
140
+ reason: "invalid",
141
+ detail: z.prettifyError(parsed.error).slice(0, 1000),
142
+ observation: source.observation,
143
+ ...identity && { identity }
144
+ };
145
+ } catch (error) {
146
+ if (missingInboxFile(error))
147
+ return null;
148
+ if (error instanceof BoundedFileReadError && error.code === "FILE_TOO_LARGE" && error.observation)
149
+ return {
150
+ reason: "too-large",
151
+ detail: error.message.slice(0, 1000),
152
+ observation: error.observation
153
+ };
154
+ throw error;
155
+ }
156
+ },
157
+ async existingIdentity(key) {
158
+ for (const name of [key, `rejected/${key}`]) {
159
+ try {
160
+ const source = await read(name);
161
+ const envelope = EnvelopeSchema.parse(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(source.bytes)));
162
+ return envelope.identity;
163
+ } catch (error) {
164
+ if (!missingInboxFile(error))
165
+ throw error;
166
+ }
167
+ }
168
+ return;
169
+ },
170
+ async publish(key, bytes, context) {
171
+ await writeAtomicFileData(join(directory, key), bytes, { replace: false, durability: "directory" }, {
172
+ open,
173
+ unlink,
174
+ async publish(staged, target, replace, directorySync) {
175
+ await context.assertHeld();
176
+ await publishAtomicFile(staged, target, replace, directorySync);
177
+ }
178
+ });
179
+ },
180
+ async remove(key, context, observation) {
181
+ if (!await matches(key, observation))
182
+ return;
183
+ await context.assertHeld();
184
+ try {
185
+ await unlink(join(directory, key));
186
+ } catch (error) {
187
+ if (!missingInboxFile(error))
188
+ throw error;
189
+ }
190
+ },
191
+ async setAside(key, context, observation) {
192
+ if (!await matches(key, observation))
193
+ return;
194
+ await mkdir(join(directory, "rejected"), { recursive: true });
195
+ await context.assertHeld();
196
+ try {
197
+ await publishAtomicFile(join(directory, key), join(directory, "rejected", key), false, true);
198
+ } catch (error) {
199
+ if (!missingInboxFile(error))
200
+ throw error;
201
+ }
202
+ }
203
+ };
204
+ }
205
+
206
+ // src/application/directory-inbox-accept.ts
207
+ function createInboxAccept(options) {
208
+ return async (input) => {
209
+ if (!options.accepting())
210
+ throw new Error("Directory inbox is not accepting entries");
211
+ const identity = DirectoryInboxIdentitySchema2.parse({
212
+ source: input.source,
213
+ key: input.key
214
+ });
215
+ const filename = inboxFilename(identity);
216
+ const bytes = encodeInboxEntry(identity, input.entry, options.schema, options.maxEntryBytes);
217
+ return options.access.update(async (state, context) => {
218
+ if (!options.accepting())
219
+ throw new Error("Directory inbox is not accepting entries");
220
+ await context.assertHeld();
221
+ const files = options.files();
222
+ const remembered = [...state.receipts, ...state.rejected, ...state.claims].find((item) => item.key === filename);
223
+ const existing = remembered?.identity ?? await files.existingIdentity(filename);
224
+ if (remembered || existing) {
225
+ if (!sameInboxIdentity(existing, identity))
226
+ throw new Error("Inbox filename belongs to a different producer identity");
227
+ return { state, result: { status: "duplicate", filename } };
228
+ }
229
+ if ((await files.names(options.maxPendingEntries)).length >= options.maxPendingEntries)
230
+ throw new RangeError("Directory inbox reached maxPendingEntries");
231
+ await context.assertHeld();
232
+ if (!options.accepting())
233
+ throw new Error("Directory inbox is not accepting entries");
234
+ await files.publish(filename, bytes, context);
235
+ return { state, result: { status: "accepted", filename } };
236
+ });
44
237
  };
45
238
  }
46
- async function entryNames(directory) {
47
- const entries = await readdir(directory, { withFileTypes: true });
48
- return entries.filter((entry) => entry.isFile() && ENTRY_NAME.test(entry.name)).map((entry) => entry.name).sort();
239
+
240
+ // src/application/directory-inbox-state.ts
241
+ function inboxStateAccess(store) {
242
+ const parse = (current) => DirectoryInboxStateSchema2.parse(current ?? emptyDirectoryInboxState());
243
+ return {
244
+ read: async () => parse(await store.read()),
245
+ update: (transition) => store.update((current, context) => transition(parse(current), context))
246
+ };
49
247
  }
50
- async function readEntry(path, schema, maxEntryBytes) {
51
- try {
52
- const { size } = await stat(path);
53
- if (size > maxEntryBytes) {
54
- return { reason: "too-large", detail: `${size} bytes over the ${maxEntryBytes} limit` };
248
+ async function cleanupInboxEntry(access, files, key, settlement, observation) {
249
+ await access.update(async (state, context) => {
250
+ if (state.claims.some((claim) => claim.key === key))
251
+ return { state, result: undefined };
252
+ if ("completedAt" in settlement) {
253
+ if (state.receipts.some((receipt) => receipt.key === key && receipt.completedAt === settlement.completedAt))
254
+ await files.remove(key, context, observation);
255
+ } else if (state.rejected.some((rejection) => rejection.key === key && rejection.rejectedAt === settlement.rejectedAt && rejection.reason === settlement.reason)) {
256
+ await files.setAside(key, context, observation);
55
257
  }
56
- const text = await readFile(path, "utf8");
57
- let json;
258
+ return { state, result: undefined };
259
+ });
260
+ }
261
+
262
+ // src/application/directory-inbox-delivery.ts
263
+ var RETRY_BACKOFF = { minDelayMs: 1000, maxDelayMs: 300000, jitter: 0 };
264
+ function createInboxDelivery(options) {
265
+ const { access, clock, config } = options;
266
+ return async (taken) => {
267
+ const controller = new AbortController;
268
+ const signal = AbortSignal.any([controller.signal, options.forced()]);
269
+ let timer;
270
+ let renewing = Promise.resolve();
271
+ const renew = () => {
272
+ renewing = access.update((state) => {
273
+ const next = renewEntry(state, taken, clock(), options.leaseMs);
274
+ return { state: next, result: next !== state };
275
+ }).then((held) => {
276
+ if (!held)
277
+ controller.abort(new Error("Inbox delivery lease was lost"));
278
+ if (!signal.aborted)
279
+ timer = setTimeout(renew, Math.max(10, Math.floor(options.leaseMs / 4)));
280
+ }).catch(async (error) => {
281
+ controller.abort(error);
282
+ await options.report(error);
283
+ });
284
+ };
285
+ if (!signal.aborted)
286
+ timer = setTimeout(renew, Math.max(10, Math.floor(options.leaseMs / 4)));
58
287
  try {
59
- json = JSON.parse(text);
60
- } catch (error) {
61
- return { reason: "invalid", detail: String(error).slice(0, 1000) };
288
+ const files = options.files();
289
+ const read = await files.read(taken.key, config.schema);
290
+ if (read === null || signal.aborted)
291
+ return false;
292
+ const claim = { ...taken, ...read.identity && { identity: read.identity } };
293
+ if ("reason" in read) {
294
+ const rejection = {
295
+ key: claim.key,
296
+ ...claim.identity && { identity: claim.identity },
297
+ reason: read.reason,
298
+ detail: read.detail,
299
+ rejectedAt: clock().toISOString()
300
+ };
301
+ const settled = await access.update((state) => {
302
+ if (signal.aborted || !ownsClaim(state, claim, clock()))
303
+ return { state, result: false };
304
+ return { state: withRejection(state, rejection, options.retain), result: true };
305
+ });
306
+ if (settled) {
307
+ await cleanupInboxEntry(access, files, claim.key, rejection, read.observation);
308
+ await config.onRejected?.(rejection);
309
+ }
310
+ return false;
311
+ }
312
+ const held = await access.update((state) => {
313
+ if (signal.aborted || !ownsClaim(state, claim, clock()))
314
+ return { state, result: false };
315
+ return {
316
+ state: {
317
+ ...state,
318
+ claims: state.claims.map((item) => item.key === claim.key ? { ...item, ...claim.identity && { identity: claim.identity } } : item)
319
+ },
320
+ result: true
321
+ };
322
+ });
323
+ if (!held || signal.aborted)
324
+ return false;
325
+ try {
326
+ await raceAbort(Promise.resolve().then(() => {
327
+ signal.throwIfAborted();
328
+ return config.handle({
329
+ key: claim.key,
330
+ ...claim.identity && { identity: claim.identity },
331
+ entry: read.entry,
332
+ attempt: claim.attempts,
333
+ signal
334
+ });
335
+ }), signal);
336
+ } catch (error) {
337
+ await options.report(error);
338
+ await access.update((state) => ({
339
+ state: signal.aborted ? state : releaseEntry(state, claim, clock(), new Date(clock().getTime() + backoffDelay(RETRY_BACKOFF, claim.attempts))),
340
+ result: undefined
341
+ }));
342
+ return false;
343
+ }
344
+ const completedAt = clock();
345
+ const completed = await access.update((state) => {
346
+ const next = signal.aborted ? state : completeEntry(state, claim, completedAt, options.retain);
347
+ return { state: next, result: next !== state };
348
+ });
349
+ if (!completed)
350
+ return false;
351
+ await cleanupInboxEntry(access, files, claim.key, { completedAt: completedAt.toISOString() }, read.observation);
352
+ return true;
353
+ } finally {
354
+ if (timer)
355
+ clearTimeout(timer);
356
+ controller.abort(new Error("Inbox delivery ended"));
357
+ await renewing;
62
358
  }
63
- const parsed = schema.safeParse(json);
64
- return parsed.success ? { entry: parsed.data } : { reason: "invalid", detail: z.prettifyError(parsed.error).slice(0, 1000) };
65
- } catch (error) {
66
- if (absent(error))
67
- return null;
68
- throw error;
69
- }
359
+ };
360
+ }
361
+
362
+ // src/application/directory-inbox.ts
363
+ function resolveLimits(config) {
364
+ const integer = z2.int();
365
+ return {
366
+ pollIntervalMs: integer.min(10).max(2147483647).parse(config.pollIntervalMs ?? 1000),
367
+ leaseMs: integer.min(100).max(2147483647).parse(config.leaseMs ?? 300000),
368
+ maxAttempts: integer.min(1).max(1e4).parse(config.maxAttempts ?? 20),
369
+ maxEntryBytes: integer.min(1).parse(config.maxEntryBytes ?? 1024 * 1024),
370
+ maxPendingEntries: integer.min(1).max(1e5).parse(config.maxPendingEntries ?? 1000),
371
+ retain: integer.min(1).max(1e5).parse(config.retain ?? 1000)
372
+ };
70
373
  }
71
374
  function createDirectoryInbox(config) {
72
375
  const limits = resolveLimits(config);
73
376
  const clock = config.clock ?? (() => new Date);
74
- const store = config.store ?? createFileStateStore2(join(config.directory, ".inbox-state.json"), {
377
+ const access = inboxStateAccess(config.store ?? createFileStateStore2(join2(config.directory, ".inbox-state.json"), {
75
378
  schema: DirectoryInboxStateSchema2
76
- });
77
- const parse = (state) => DirectoryInboxStateSchema2.parse(state ?? emptyDirectoryInboxState());
78
- const update = (transition) => store.update((current) => transition(parse(current)));
379
+ }));
380
+ let files;
381
+ const filesFor = () => {
382
+ if (!files)
383
+ throw new Error("Directory inbox has not started");
384
+ return files;
385
+ };
79
386
  let running = false;
80
387
  let admitting = false;
388
+ let accepting = false;
81
389
  let timer;
82
390
  let forced = new AbortController;
83
391
  let tail = Promise.resolve();
392
+ const pendingAccepts = new Set;
84
393
  const report = async (error) => {
85
394
  try {
86
395
  await config.onError?.(error);
87
396
  } catch {}
88
397
  };
89
- const setAside = async (key, rejection) => {
90
- await mkdir(join(config.directory, REJECTED), { recursive: true });
91
- await quietly(() => rename(join(config.directory, key), join(config.directory, REJECTED, key)));
92
- if (rejection)
93
- await config.onRejected?.(rejection);
94
- };
95
- const reject = async (key, reason, detail) => {
96
- const rejection = { key, reason, detail, rejectedAt: clock().toISOString() };
97
- await update((state) => ({
98
- state: withRejection(state, rejection, limits.retain),
99
- result: undefined
100
- }));
101
- await setAside(key, rejection);
102
- };
103
- const deliver = async (claim) => {
104
- const path = join(config.directory, claim.key);
105
- const read = await readEntry(path, config.schema, limits.maxEntryBytes);
106
- if (read === null)
107
- return false;
108
- if ("reason" in read) {
109
- await reject(claim.key, read.reason, read.detail);
110
- return false;
111
- }
112
- try {
113
- await config.handle({
114
- key: claim.key,
115
- entry: read.entry,
116
- attempt: claim.attempts,
117
- signal: forced.signal
118
- });
119
- } catch (error) {
120
- await report(error);
121
- const retryAt = new Date(clock().getTime() + backoffDelay(RETRY_BACKOFF, claim.attempts));
122
- await update((state) => ({
123
- state: releaseEntry(state, claim, retryAt),
124
- result: undefined
125
- }));
126
- return false;
127
- }
128
- await update((state) => ({
129
- state: completeEntry(state, claim.key, clock(), limits.retain),
130
- result: undefined
131
- }));
132
- await quietly(() => unlink(path));
133
- return true;
134
- };
398
+ const deliver = createInboxDelivery({
399
+ config,
400
+ access,
401
+ files: filesFor,
402
+ clock,
403
+ forced: () => forced.signal,
404
+ leaseMs: limits.leaseMs,
405
+ retain: limits.retain,
406
+ report
407
+ });
135
408
  const pass = async () => {
136
- const names = await entryNames(config.directory);
137
- await update((state) => ({
409
+ if (!accepting || forced.signal.aborted)
410
+ return 0;
411
+ const currentFiles = filesFor();
412
+ const names = await currentFiles.names();
413
+ await access.update((state) => ({
138
414
  state: forgetMissing(state, new Set(names), clock()),
139
415
  result: undefined
140
416
  }));
141
417
  let handled = 0;
142
418
  for (const key of names) {
143
- if (!admitting && running)
419
+ if (!accepting || forced.signal.aborted || running && !admitting)
144
420
  break;
145
- const { step } = await update((state) => {
421
+ const step = await access.update((state) => {
146
422
  const next = claimEntry(state, { key, now: clock(), ...limits });
147
- return { state: next.state, result: next };
423
+ return { state: next.state, result: next.step };
148
424
  });
149
- if (step.kind === "remove")
150
- await quietly(() => unlink(join(config.directory, key)));
151
- else if (step.kind === "set-aside")
152
- await setAside(key);
153
- else if (step.kind === "reject")
154
- await setAside(key, step.rejection);
155
- else if (step.kind === "deliver" && await deliver(step.claim))
156
- handled += 1;
425
+ if (step.kind === "deliver") {
426
+ if (await deliver(step.claim))
427
+ handled += 1;
428
+ } else if (step.kind === "reject") {
429
+ await cleanupInboxEntry(access, currentFiles, key, step.rejection);
430
+ await config.onRejected?.(step.rejection);
431
+ } else if (step.kind === "remove" || step.kind === "set-aside") {
432
+ await access.update(async (state, context) => {
433
+ if (state.claims.some((claim) => claim.key === key))
434
+ return { state, result: undefined };
435
+ const terminal = step.kind === "remove" ? state.receipts.some((receipt) => receipt.key === key) : state.rejected.some((rejection) => rejection.key === key);
436
+ if (terminal) {
437
+ await context.assertHeld();
438
+ if (step.kind === "remove")
439
+ await currentFiles.remove(key, context);
440
+ else
441
+ await currentFiles.setAside(key, context);
442
+ }
443
+ return { state, result: undefined };
444
+ });
445
+ }
157
446
  }
158
447
  return handled;
159
448
  };
@@ -175,22 +464,42 @@ function createDirectoryInbox(config) {
175
464
  };
176
465
  const stopAdmitting = () => {
177
466
  admitting = false;
467
+ accepting = false;
178
468
  if (timer)
179
469
  clearTimeout(timer);
180
470
  timer = undefined;
181
471
  };
472
+ const accept = createInboxAccept({
473
+ access,
474
+ files: filesFor,
475
+ accepting: () => accepting,
476
+ schema: config.schema,
477
+ maxEntryBytes: limits.maxEntryBytes,
478
+ maxPendingEntries: limits.maxPendingEntries
479
+ });
480
+ const drained = async () => {
481
+ await Promise.allSettled([...pendingAccepts]);
482
+ await tail;
483
+ };
182
484
  const inbox = {
485
+ accept(input) {
486
+ const result = accept(input);
487
+ pendingAccepts.add(result);
488
+ result.then(() => pendingAccepts.delete(result), () => pendingAccepts.delete(result));
489
+ return result;
490
+ },
183
491
  flush,
184
- async state() {
185
- return parse(await store.read());
186
- }
492
+ state: access.read
187
493
  };
188
494
  return defineManagedResource2({
189
495
  id: config.id,
190
496
  ...config.dependsOn && { dependsOn: config.dependsOn },
191
497
  async start() {
192
- await mkdir(config.directory, { recursive: true });
498
+ await mkdir2(config.directory, { recursive: true });
499
+ files = await createInboxFiles(config.directory, limits.maxEntryBytes);
193
500
  forced = new AbortController;
501
+ running = false;
502
+ accepting = true;
194
503
  return { value: inbox };
195
504
  },
196
505
  activate() {
@@ -198,20 +507,16 @@ function createDirectoryInbox(config) {
198
507
  admitting = true;
199
508
  poll();
200
509
  },
201
- stopAdmission() {
202
- stopAdmitting();
203
- },
204
- async drain() {
205
- await tail;
206
- },
510
+ stopAdmission: stopAdmitting,
511
+ drain: drained,
207
512
  async close() {
208
513
  stopAdmitting();
209
- await tail;
514
+ await drained();
210
515
  },
211
516
  async force() {
212
517
  stopAdmitting();
213
- forced.abort();
214
- await tail;
518
+ forced.abort(new Error("Directory inbox was forced down"));
519
+ await drained();
215
520
  }
216
521
  });
217
522
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AppError2
3
- } from "../../index-n53mswt3.js";
3
+ } from "../../index-x928baz2.js";
4
4
  import {
5
5
  defineManagedResource2
6
6
  } from "../../index-50ejfz75.js";
@@ -4,7 +4,7 @@ export { type ChangeConnection, type ChangeReconciliation, type ChangeSubscripti
4
4
  export { createDecisionPipeline, type DecisionPipeline, type DecisionPipelineConfig, type DecisionPolicy, DecisionPolicyError, type DecisionResult, type DecisionTraceEntry, DecisionUndecidedError, type PolicyDecision, PolicyDecisionSchema, } from '../application/decisions.js';
5
5
  export { type DiagnosticJournal, type DiagnosticJournalCloseResult, DiagnosticJournalCloseResultSchema, type DiagnosticJournalConfig, type DiagnosticJournalFailure, type DiagnosticJournalFailurePhase, DiagnosticJournalFailurePhaseSchema, type DiagnosticJournalFrame, DiagnosticJournalFrameSchema, type DiagnosticJournalLimits, DiagnosticJournalLimitsSchema, type DiagnosticJournalLockDiagnosis, type DiagnosticJournalLockPolicy, DiagnosticJournalLockPolicySchema, type DiagnosticJournalRefusalReason, DiagnosticJournalRefusalReasonSchema, type DiagnosticJournalState, DiagnosticJournalStateSchema, type DiagnosticJournalStatus, DiagnosticJournalStatusSchema, type DiagnosticJournalSubmitResult, DiagnosticJournalSubmitResultSchema, type DiagnosticJournalWaitOptions, type DiagnosticJournalWaitResult, DiagnosticJournalWaitResultSchema, readDiagnosticJournalLockDiagnosis, } from '../application/diagnostic-journal-contract.js';
6
6
  export { createDiagnosticJournalReadResultSchema, type DiagnosticJournalAnomaly, DiagnosticJournalAnomalySchema, type DiagnosticJournalReadResult, DiagnosticJournalRecoveryError, type DiagnosticJournalRecoveryStatus, DiagnosticJournalRecoveryStatusSchema, } from '../application/diagnostic-journal-read-contract.js';
7
- export { type DirectoryInbox, type DirectoryInboxConfig, type DirectoryInboxDelivery, type DirectoryInboxRejection, type DirectoryInboxRejectionReason, DirectoryInboxRejectionReasonSchema, type DirectoryInboxResource, type DirectoryInboxState, DirectoryInboxStateSchema, } from '../application/directory-inbox-contract.js';
7
+ export { type DirectoryInbox, type DirectoryInboxAccept, type DirectoryInboxAcceptResult, DirectoryInboxAcceptResultSchema, type DirectoryInboxConfig, type DirectoryInboxDelivery, type DirectoryInboxIdentity, DirectoryInboxIdentitySchema, type DirectoryInboxRejection, type DirectoryInboxRejectionReason, DirectoryInboxRejectionReasonSchema, type DirectoryInboxResource, type DirectoryInboxState, DirectoryInboxStateSchema, } from '../application/directory-inbox-contract.js';
8
8
  export { type ApplicationEventSink, type ApplicationEventSinkConfig, type ApplicationLifecycleEvent, ApplicationLifecycleEventSchema, applicationLifecycleEvent, createApplicationEventSink, } from '../application/events.js';
9
9
  export { type ApplicationHealthHandlerOptions, ApplicationHealthHandlerOptionsSchema, type ApplicationOperationalHandlers, type ApplicationOperationalHandlersOptions, ApplicationOperationalHandlersOptionsSchema, createApplicationHealthHandler, createApplicationOperationalHandlers, } from '../application/health.js';
10
10
  export { createApplication } from '../application/kernel.js';
@@ -20,7 +20,7 @@ export { defineManagedResource, type ManagedResource, type ManagedResourceAdmiss
20
20
  export { createRevisionSignal, type RevisionSignal, type RevisionSignalAdvanceResult, RevisionSignalAdvanceResultSchema, type RevisionSignalClock, type RevisionSignalConfig, type RevisionSignalSnapshot, RevisionSignalSnapshotSchema, type RevisionSignalState, RevisionSignalStateSchema, type RevisionSignalTimer, type RevisionSignalWaitOptions, type RevisionSignalWaitOutcome, RevisionSignalWaitOutcomeSchema, type RevisionSignalWaitResult, RevisionSignalWaitResultSchema, } from '../application/revision-signal.js';
21
21
  export { createManagedSchedule, type ManagedSchedule, type ManagedScheduleClock, type ManagedScheduleConfig, type ManagedScheduleDescriptor, ManagedScheduleDescriptorSchema, type ManagedScheduleErrorPolicy, ManagedScheduleErrorPolicySchema, type ManagedScheduleOverlap, ManagedScheduleOverlapSchema, type ManagedScheduleRunContext, type ManagedScheduleStatus, ManagedScheduleStatusSchema, type ManagedScheduleTimer, } from '../application/schedule.js';
22
22
  export { type ManagedServerResource, type ManagedServerResourceConfig, managedServerResource, } from '../application/server-resource.js';
23
- export type { StateStore, StateStoreUpdate } from '../application/state-store.js';
23
+ export type { StateStore, StateStoreUpdate, StateStoreUpdateContext, } from '../application/state-store.js';
24
24
  export { type AttachedWatcher, createWatchHub, type WatchAdmissionScope, type WatchHub, type WatchHubConfig, type WatchOperation, type WatchSubscriber, watchKey, } from '../application/watch-hub.js';
25
25
  export { type BoundedChannel, type BoundedChannelCloseOptions, type BoundedChannelConfig, type BoundedChannelOfferResult, type BoundedChannelPolicy, BoundedChannelPolicySchema, BoundedChannelReaderError, type BoundedChannelSnapshot, BoundedChannelSnapshotSchema, type BoundedChannelState, BoundedChannelStateSchema, type CreditAcquireResult, type CreditAcquireWaitOptions, type CreditLease, type CreditWaitRefusalReason, type CreditWaitResult, type CreditWindow, type CreditWindowSnapshot, CreditWindowSnapshotSchema, createBoundedChannel, createCreditWindow, } from '../internal/channel.js';
26
26
  export type { SqliteDatabase, SqliteStatement, SqliteValue } from '../internal/sqlite.js';