apps 0.0.1-beta.4 → 0.0.1-beta.41

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 (171) hide show
  1. package/README.md +68 -44
  2. package/framework-reference.json +1 -1
  3. package/js/{chunk-QKHR7BMF.js → chunk-3MMG2H6M.js} +89 -53
  4. package/js/{chunk-EQB7JMAL.js → chunk-6XGB4BAL.js} +146 -31
  5. package/js/chunk-ADD6H64X.js +729 -0
  6. package/js/{chunk-6VRYO2BG.js → chunk-AHGGO2VY.js} +837 -254
  7. package/js/{chunk-FDNTX5QJ.js → chunk-CQD3WSYH.js} +2 -2
  8. package/js/{chunk-EVJUVWN2.js → chunk-DKUEYTYD.js} +463 -218
  9. package/js/chunk-EM4UL26F.js +118 -0
  10. package/js/{chunk-2VPJHFOU.js → chunk-FXWRE655.js} +128 -24
  11. package/js/{chunk-5MQZEB6Y.js → chunk-JI3EP2GL.js} +40 -12
  12. package/js/chunk-JJSLEJ6T.js +156 -0
  13. package/js/chunk-KAQD3DTI.js +16 -0
  14. package/js/chunk-KIM5HXNK.js +49 -0
  15. package/js/chunk-MJZYV7IO.js +255 -0
  16. package/js/{chunk-FW5HBOIK.js → chunk-MXDKXAY4.js} +19117 -18309
  17. package/js/{chunk-T2LAZCAD.js → chunk-NKWWPJYX.js} +3 -3
  18. package/js/chunk-OD3KFKZD.js +1617 -0
  19. package/js/{chunk-3M2MEDNL.js → chunk-OTCLXFLL.js} +1337 -188
  20. package/js/chunk-P7MGDPFD.js +240 -0
  21. package/js/{chunk-ZCAMUXSG.js → chunk-PNVCCB4L.js} +432 -79
  22. package/js/{chunk-D47C7KG5.js → chunk-RIXVGVA6.js} +2 -2
  23. package/js/{chunk-NQ3OMCA5.js → chunk-TT6OU4UG.js} +2 -2
  24. package/js/{chunk-YEJOQEII.js → chunk-UOZMSUJ2.js} +61 -9
  25. package/js/chunk-UTJIGUSS.js +42 -0
  26. package/js/{chunk-G7ZIRKMK.js → chunk-VIU2XXA7.js} +228 -264
  27. package/js/{chunk-HDJH3RPR.js → chunk-VJQXXOQ3.js} +4 -4
  28. package/js/{chunk-WFSQXYUT.js → chunk-WPBR4AWB.js} +523 -63
  29. package/js/{chunk-SATWJKN6.js → chunk-YQ35E7KS.js} +2 -2
  30. package/js/chunk-ZUKBIHMK.js +92 -0
  31. package/js/client.js +122 -88
  32. package/js/contracts.js +116 -25
  33. package/js/effect.js +19 -20
  34. package/js/{es-APDZKREY.js → es-DIULA3ZF.js} +62 -1659
  35. package/js/graphql.js +57 -55
  36. package/js/host.js +19 -20
  37. package/js/index.js +245 -212
  38. package/js/mcp/effect.js +23 -22
  39. package/js/mcp/stdio.js +34 -30
  40. package/js/mcp.js +104 -68
  41. package/js/openapi.js +4087 -1503
  42. package/js/react.js +2 -3
  43. package/js/skills/effect.js +6 -3
  44. package/js/skills.js +147 -65
  45. package/js/storage/facet.js +1 -540
  46. package/js/ui/auth/contracts.js +2 -2
  47. package/js/ui/auth.js +5 -5
  48. package/js/ui/contracts.js +5 -4
  49. package/js/ui/serving.js +8517 -214
  50. package/package.json +2 -3
  51. package/runtime.json +1 -1
  52. package/types/app-data/src/contracts/database.d.ts +33 -6
  53. package/types/apps/src/contracts/api-response-error.d.ts +4 -0
  54. package/types/apps/src/contracts/app.d.ts +7 -8
  55. package/types/apps/src/contracts/cache.d.ts +14 -0
  56. package/types/apps/src/contracts/context.d.ts +12 -11
  57. package/types/apps/src/contracts/elicitation.d.ts +6 -6
  58. package/types/apps/src/contracts/failure.d.ts +54 -0
  59. package/types/apps/src/contracts/graphql.d.ts +2 -1
  60. package/types/apps/src/contracts/host.d.ts +44 -17
  61. package/types/apps/src/contracts/live.d.ts +2 -0
  62. package/types/apps/src/contracts/mcp.d.ts +96 -10
  63. package/types/apps/src/contracts/network.d.ts +84 -0
  64. package/types/apps/src/contracts/openapi-compile.d.ts +32 -3
  65. package/types/apps/src/contracts/openapi.d.ts +45 -9
  66. package/types/apps/src/contracts/operations.d.ts +8 -9
  67. package/types/apps/src/contracts/protocol-version.d.ts +2 -2
  68. package/types/apps/src/contracts/protocols/1.d.ts +263 -74
  69. package/types/apps/src/contracts/protocols/10.d.ts +1450 -0
  70. package/types/apps/src/contracts/protocols/2.d.ts +66 -24
  71. package/types/apps/src/contracts/protocols/3.d.ts +715 -0
  72. package/types/apps/src/contracts/protocols/4.d.ts +1297 -0
  73. package/types/apps/src/contracts/protocols/5.d.ts +1174 -0
  74. package/types/apps/src/contracts/protocols/6.d.ts +1620 -0
  75. package/types/apps/src/contracts/protocols/7.d.ts +1784 -0
  76. package/types/apps/src/contracts/protocols/8.d.ts +1130 -0
  77. package/types/apps/src/contracts/protocols/9.d.ts +1106 -0
  78. package/types/apps/src/contracts/protocols/oauth.d.ts +89 -0
  79. package/types/apps/src/contracts/provider-error.d.ts +9 -0
  80. package/types/apps/src/contracts/provider.d.ts +115 -10
  81. package/types/apps/src/contracts/router.d.ts +59 -0
  82. package/types/apps/src/contracts/skills.d.ts +39 -9
  83. package/types/apps/src/contracts/sql.d.ts +58 -0
  84. package/types/apps/src/contracts/ui.d.ts +19 -1
  85. package/types/apps/src/contracts/workflows.d.ts +40 -3
  86. package/types/apps/src/facet.d.ts +4 -5
  87. package/types/apps/src/graphql.d.ts +1 -3
  88. package/types/apps/src/implementation/account-router.d.ts +12 -0
  89. package/types/apps/src/implementation/app.d.ts +5 -4
  90. package/types/apps/src/implementation/browser-scripts.gen.d.ts +6 -0
  91. package/types/apps/src/implementation/catalog-cache.d.ts +32 -5
  92. package/types/apps/src/implementation/elicitation.d.ts +12 -12
  93. package/types/apps/src/implementation/failure-detail.d.ts +47 -0
  94. package/types/apps/src/implementation/graphql-catalog.d.ts +4 -7
  95. package/types/apps/src/implementation/graphql.d.ts +4 -3
  96. package/types/apps/src/implementation/input-problems.d.ts +6 -2
  97. package/types/apps/src/implementation/live.d.ts +2 -2
  98. package/types/apps/src/implementation/mcp-call.d.ts +6 -5
  99. package/types/apps/src/implementation/mcp-catalog.d.ts +7 -8
  100. package/types/apps/src/implementation/mcp-client.d.ts +49 -25
  101. package/types/apps/src/implementation/mcp-stdio.d.ts +1 -1
  102. package/types/apps/src/implementation/mcp-tools.d.ts +2 -1
  103. package/types/apps/src/implementation/mcp.d.ts +52 -25
  104. package/types/apps/src/implementation/network.d.ts +16 -0
  105. package/types/apps/src/implementation/openapi-compile.d.ts +27 -6
  106. package/types/apps/src/implementation/openapi-document.d.ts +46 -19
  107. package/types/apps/src/implementation/openapi-names.d.ts +9 -4
  108. package/types/apps/src/implementation/openapi-request.d.ts +10 -2
  109. package/types/apps/src/implementation/openapi-source.d.ts +8 -6
  110. package/types/apps/src/implementation/openapi-upgrade.d.ts +4 -0
  111. package/types/apps/src/implementation/operations.d.ts +36 -3
  112. package/types/apps/src/implementation/optimistic.d.ts +1 -1
  113. package/types/apps/src/implementation/protocol-operations.d.ts +6 -4
  114. package/types/apps/src/implementation/provider-error.d.ts +28 -1
  115. package/types/apps/src/implementation/provider.d.ts +19 -5
  116. package/types/apps/src/implementation/query-commit.d.ts +1 -1
  117. package/types/apps/src/implementation/router-catalog.d.ts +223 -0
  118. package/types/apps/src/implementation/router.d.ts +68 -0
  119. package/types/apps/src/implementation/runtime-yield.d.ts +7 -0
  120. package/types/apps/src/implementation/schema.d.ts +95 -11
  121. package/types/apps/src/implementation/skills.d.ts +18 -24
  122. package/types/apps/src/implementation/sql.d.ts +66 -0
  123. package/types/apps/src/implementation/ui-account-notice.d.ts +9 -0
  124. package/types/apps/src/implementation/ui-auth.d.ts +1 -1
  125. package/types/apps/src/implementation/ui-client.d.ts +2 -2
  126. package/types/apps/src/implementation/ui-document.d.ts +5 -0
  127. package/types/apps/src/implementation/ui-errors.d.ts +1 -1
  128. package/types/apps/src/implementation/ui-serving.d.ts +11 -5
  129. package/types/apps/src/implementation/ui-watch.d.ts +1 -1
  130. package/types/apps/src/implementation/upstream-error.d.ts +7 -0
  131. package/types/apps/src/implementation/webhooks.d.ts +1 -1
  132. package/types/apps/src/implementation/workflow-context.d.ts +11 -3
  133. package/types/apps/src/index.d.ts +30 -13
  134. package/types/apps/src/mcp-stdio.d.ts +2 -5
  135. package/types/apps/src/mcp.d.ts +25 -5
  136. package/types/apps/src/openapi.d.ts +6 -6
  137. package/types/apps/src/react.d.ts +1 -1
  138. package/types/apps/src/skills.d.ts +10 -8
  139. package/types/telemetry/src/app-records.d.ts +42 -0
  140. package/types/telemetry/src/browser-operations.d.ts +6 -3
  141. package/types/telemetry/src/browser.d.ts +2 -2
  142. package/types/telemetry/src/config.d.ts +2 -2
  143. package/types/telemetry/src/layer.d.ts +2 -2
  144. package/types/telemetry/src/recorded-failure.d.ts +20 -0
  145. package/types/telemetry/src/relay.d.ts +2 -2
  146. package/types/telemetry/src/transport.d.ts +8 -1
  147. package/types/utils/src/api-error.d.ts +53 -0
  148. package/types/utils/src/recorded-message.d.ts +15 -0
  149. package/js/chunk-BMOIAIVR.js +0 -138
  150. package/js/chunk-DHUDODG5.js +0 -213
  151. package/js/chunk-FZJOYIZO.js +0 -19
  152. package/js/chunk-LGIYBDWA.js +0 -85
  153. package/js/chunk-M6ZRRIBI.js +0 -877
  154. package/js/chunk-PLCMJREA.js +0 -590
  155. package/js/chunk-PYUYJRSK.js +0 -93
  156. package/js/chunk-SWPD52J7.js +0 -35
  157. package/js/chunk-W7D7WVSY.js +0 -18
  158. package/js/chunk-Z5NMEGJN.js +0 -29
  159. package/js/chunk-ZJWDMTE3.js +0 -63
  160. package/types/app-data/src/implementation/cursor.d.ts +0 -10
  161. package/types/app-data/src/implementation/index-key.d.ts +0 -7
  162. package/types/app-data/src/implementation/promise.d.ts +0 -68
  163. package/types/app-data/src/implementation/range.d.ts +0 -8
  164. package/types/app-data/src/implementation/schema.d.ts +0 -33
  165. package/types/app-data/src/implementation/sqlite.d.ts +0 -11
  166. package/types/app-data/src/index.d.ts +0 -4
  167. package/types/apps/src/contracts/dynamic-tools.d.ts +0 -13
  168. package/types/apps/src/contracts/storage.d.ts +0 -68
  169. package/types/apps/src/implementation/account-operations.d.ts +0 -151
  170. package/types/apps/src/implementation/dynamic-tools.d.ts +0 -8
  171. package/types/apps/src/implementation/storage.d.ts +0 -13
@@ -1,24 +1,42 @@
1
1
  import {
2
2
  makeCache
3
- } from "./chunk-D47C7KG5.js";
3
+ } from "./chunk-RIXVGVA6.js";
4
+ import {
5
+ accountSecrets,
6
+ boundFailureMessage,
7
+ describeFailure,
8
+ failureDetail,
9
+ leavingProviderError,
10
+ parseMcpError,
11
+ parseSkillLoadFailed,
12
+ readCatalog,
13
+ routerSkills
14
+ } from "./chunk-ADD6H64X.js";
15
+ import {
16
+ appInvocationFetch
17
+ } from "./chunk-KIM5HXNK.js";
4
18
  import {
5
19
  folderSkillsEffect
6
- } from "./chunk-FDNTX5QJ.js";
20
+ } from "./chunk-CQD3WSYH.js";
7
21
  import {
8
- authorDatabase,
22
+ ResponseStatusError,
9
23
  isApp,
10
- toEffectApp,
11
- unavailableStorage
12
- } from "./chunk-DHUDODG5.js";
24
+ toEffectApp
25
+ } from "./chunk-JJSLEJ6T.js";
13
26
  import {
27
+ declaredOperations,
14
28
  fromPromise,
29
+ locate,
15
30
  nativeOperation,
16
31
  toPromise
17
- } from "./chunk-PYUYJRSK.js";
32
+ } from "./chunk-MJZYV7IO.js";
18
33
  import {
34
+ accountProviderError,
35
+ httpProviderError,
19
36
  parseProviderError
20
- } from "./chunk-ZJWDMTE3.js";
37
+ } from "./chunk-EM4UL26F.js";
21
38
  import {
39
+ AccountCheckResult,
22
40
  DeclaredProvider,
23
41
  DeclaredRequirements,
24
42
  ElicitationFailed,
@@ -29,6 +47,7 @@ import {
29
47
  HostError,
30
48
  HostEvaluationFailed,
31
49
  HostInputInvalid,
50
+ HostKindMismatch,
32
51
  HostOperationFailed,
33
52
  HostOperationNotFound,
34
53
  HostOutputInvalid,
@@ -38,6 +57,7 @@ import {
38
57
  HostToolBlocked,
39
58
  HostToolNotFound,
40
59
  HostToolPolicyFailed,
60
+ HostedRouter,
41
61
  HostedTool,
42
62
  HostedToolSummary,
43
63
  HostedWebhook,
@@ -45,9 +65,8 @@ import {
45
65
  InvocationDeadline,
46
66
  ManualWebhookSetup,
47
67
  ManyAccounts,
48
- McpError,
49
68
  NonRetryableError,
50
- OperationToolPrefixes,
69
+ OpenapiResponseError,
51
70
  ResolvedAccounts,
52
71
  ToolResultObservation,
53
72
  TrustedToolApproval,
@@ -61,44 +80,51 @@ import {
61
80
  approvalElicitation,
62
81
  defaultWebhookTransportLimits,
63
82
  maxInputProblems,
83
+ migrationsDirectory,
84
+ reservedTablePrefix,
64
85
  workflowDurationMillis
65
- } from "./chunk-3M2MEDNL.js";
86
+ } from "./chunk-OTCLXFLL.js";
66
87
  import {
67
88
  CacheError
68
- } from "./chunk-LGIYBDWA.js";
89
+ } from "./chunk-P7MGDPFD.js";
69
90
  import {
70
91
  AppSkills,
71
- SkillFile,
72
- SkillLoadFailed
73
- } from "./chunk-YEJOQEII.js";
92
+ SkillFile
93
+ } from "./chunk-UOZMSUJ2.js";
74
94
  import {
75
- OpenapiResponseError
76
- } from "./chunk-SWPD52J7.js";
77
- import {
78
- captureTelemetry,
79
- invocationFetch
80
- } from "./chunk-ZCAMUXSG.js";
95
+ captureTelemetry
96
+ } from "./chunk-PNVCCB4L.js";
81
97
  import {
98
+ allowedValues,
82
99
  decoderOf,
100
+ echoableKey,
83
101
  importedJsonSchema,
84
- jsonSchemaDecoder
85
- } from "./chunk-WFSQXYUT.js";
102
+ importedSchemaKeys,
103
+ jsonSchemaDecoder,
104
+ jsonSchemaDocument,
105
+ maxAlternativeKeys,
106
+ missingKey,
107
+ missingKeyText,
108
+ objectShape,
109
+ unionShape
110
+ } from "./chunk-WPBR4AWB.js";
86
111
  import {
87
112
  JsonObject,
88
113
  JsonValue
89
- } from "./chunk-SATWJKN6.js";
114
+ } from "./chunk-YQ35E7KS.js";
90
115
  import {
116
+ Base64_exports,
91
117
  Cause_exports,
92
118
  Clock_exports,
93
119
  Effect_exports,
94
- Encoding_exports,
95
120
  Match_exports,
96
121
  Option_exports,
97
122
  Redacted_exports,
123
+ SchemaAST_exports,
98
124
  SchemaIssue_exports,
99
125
  Schema_exports,
100
126
  Stream_exports
101
- } from "./chunk-FW5HBOIK.js";
127
+ } from "./chunk-MXDKXAY4.js";
102
128
 
103
129
  // src/implementation/elicitation.ts
104
130
  var prepareElicitation = (input) => Effect_exports.gen(function* () {
@@ -139,19 +165,29 @@ var makeElicit = (handler, signal) => toPromise(
139
165
  var ApprovalDecision = Schema_exports.Literals(["approved", "denied", "user-approval"]);
140
166
 
141
167
  // src/implementation/workflow-context.ts
142
- var workflowSafe = (work) => work.pipe(
168
+ var workflowSafe = (work, secrets) => work.pipe(
143
169
  Effect_exports.catchCause((cause) => {
144
170
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
145
171
  const error = Cause_exports.squash(cause);
146
172
  if (Schema_exports.is(WorkflowFailure)(error)) return Effect_exports.fail(error);
173
+ const { errorName, message } = failureDetail(error, secrets);
147
174
  return Effect_exports.fail(
148
175
  new WorkflowFailure({
149
176
  reason: "execution",
150
- retryable: !(error instanceof NonRetryableError)
177
+ retryable: !(error instanceof NonRetryableError),
178
+ ...errorName === void 0 ? {} : { errorName },
179
+ ...message === void 0 ? {} : { message }
151
180
  })
152
181
  );
153
182
  })
154
183
  );
184
+ var inStep = (step) => (failure) => failure.step === void 0 ? new WorkflowFailure({
185
+ reason: failure.reason,
186
+ retryable: failure.retryable,
187
+ step: step.slice(0, 200),
188
+ ...failure.errorName === void 0 ? {} : { errorName: failure.errorName },
189
+ ...failure.message.length === 0 ? {} : { message: failure.message }
190
+ }) : failure;
155
191
  var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_exports.gen(function* () {
156
192
  const services = yield* Effect_exports.context();
157
193
  const counts = /* @__PURE__ */ new Map();
@@ -206,25 +242,33 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
206
242
  Effect_exports.sync(() => new AbortController()),
207
243
  (controller2) => Effect_exports.sync(() => controller2.abort())
208
244
  );
209
- const ctx = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
245
+ const step2 = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
210
246
  const result = yield* workflowSafe(
211
- Effect_exports.tryPromise({ try: () => callback(ctx), catch: (error) => error })
247
+ Effect_exports.tryPromise({
248
+ try: () => callback(step2.context),
249
+ catch: (error) => error
250
+ }),
251
+ step2.secrets
212
252
  );
213
253
  return yield* Schema_exports.decodeUnknownEffect(WorkflowValue)(result).pipe(
214
254
  Effect_exports.mapError(
215
- () => new WorkflowFailure({ reason: "output", retryable: false })
255
+ () => new WorkflowFailure({
256
+ reason: "output",
257
+ retryable: false,
258
+ message: "The step returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
259
+ })
216
260
  )
217
261
  );
218
262
  })
219
263
  ).pipe(Effect_exports.provideContext(services))
220
264
  )
221
- );
265
+ ).pipe(Effect_exports.mapError(inStep(name)));
222
266
  });
223
267
  const operationStep = (kind, name, operation, input, options) => Effect_exports.gen(function* () {
224
268
  const target = nativeOperation(operation);
225
- const catalog = kind === "query" ? definition.queries : definition.mutations;
226
- const match = Object.entries(catalog ?? {}).find(
227
- ([, value]) => value === target && value.kind === kind
269
+ const root = definition.tools?.kind === "router" ? definition.tools : void 0;
270
+ const match = declaredOperations(root).find(
271
+ (entry) => entry.operation === target && entry.operation.kind === kind
228
272
  );
229
273
  if (target === void 0 || match === void 0)
230
274
  return yield* new WorkflowFailure({ reason: "operation", retryable: false });
@@ -243,9 +287,9 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
243
287
  parsed,
244
288
  () => attempt(
245
289
  parsed,
246
- execution.invoke({ kind, name: match[0], input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
290
+ execution.invoke({ kind, name: match.name, input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
247
291
  )
248
- );
292
+ ).pipe(Effect_exports.mapError(inStep(name)));
249
293
  });
250
294
  const invoke = (effect) => toPromise(() => effect.pipe(Effect_exports.provideContext(services)), signal)();
251
295
  const step = {
@@ -284,15 +328,144 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
284
328
  });
285
329
 
286
330
  // src/implementation/input-problems.ts
287
- var leafHook = (issue) => SchemaIssue_exports.hasInput(issue) ? "Invalid value" : SchemaIssue_exports.defaultLeafHook(issue);
331
+ var nativeObjectShape = (ast, limit) => objectShape(
332
+ ast.propertySignatures.flatMap(
333
+ ({ name, type }) => typeof name === "string" ? [{ name, optional: SchemaAST_exports.isOptional(SchemaAST_exports.toEncoded(type)) }] : []
334
+ ),
335
+ ast.indexSignatures.length > 0,
336
+ limit
337
+ );
338
+ var unionMembers = (ast) => SchemaAST_exports.isUnion(ast) ? ast.types.flatMap(unionMembers) : SchemaAST_exports.isUndefined(ast) || SchemaAST_exports.isVoid(ast) ? [] : [ast];
339
+ var fixedValues = (ast) => {
340
+ if (SchemaAST_exports.isLiteral(ast)) return [ast.literal];
341
+ if (SchemaAST_exports.isEnum(ast)) return ast.enums.map(([, value]) => value);
342
+ if (!SchemaAST_exports.isUnion(ast)) return void 0;
343
+ const members = unionMembers(ast).map(fixedValues);
344
+ return members.length > 0 && members.every((values) => values !== void 0) ? members.flat() : void 0;
345
+ };
346
+ var describeMember = (ast) => Match_exports.value(ast).pipe(
347
+ Match_exports.when(
348
+ SchemaAST_exports.isObjects,
349
+ (objects) => objects.propertySignatures.length > 0 ? nativeObjectShape(objects, maxAlternativeKeys) : "object"
350
+ ),
351
+ Match_exports.when(SchemaAST_exports.isArrays, () => "array"),
352
+ Match_exports.when(SchemaAST_exports.isTemplateLiteral, () => "a string matching a template"),
353
+ Match_exports.when(SchemaAST_exports.isString, () => "string"),
354
+ Match_exports.when(SchemaAST_exports.isNumber, () => "number"),
355
+ Match_exports.when(SchemaAST_exports.isBoolean, () => "boolean"),
356
+ Match_exports.when(SchemaAST_exports.isNull, () => "null"),
357
+ Match_exports.orElse(() => "a value with other constraints")
358
+ );
359
+ var memberSelector = (members) => {
360
+ const [first] = members;
361
+ if (members.length < 2 || first === void 0 || !SchemaAST_exports.isObjects(first)) return void 0;
362
+ return first.propertySignatures.map(({ name }) => name).find(
363
+ (name) => typeof name === "string" && members.every(
364
+ (member) => SchemaAST_exports.isObjects(member) && member.propertySignatures.some(
365
+ (property) => property.name === name && fixedValues(SchemaAST_exports.toEncoded(property.type)) !== void 0
366
+ )
367
+ )
368
+ );
369
+ };
370
+ var unionExpectation = (ast) => {
371
+ const members = unionMembers(ast);
372
+ const fixed = members.map(fixedValues);
373
+ const values = fixed.flatMap((memberValues) => memberValues === void 0 ? [] : memberValues);
374
+ const others = members.filter((_, index) => fixed[index] === void 0);
375
+ if (others.length === 0) return allowedValues(values);
376
+ return unionShape(
377
+ [
378
+ ...values.length === 0 ? [] : [allowedValues(values)],
379
+ ...new Set(others.map(describeMember))
380
+ ],
381
+ memberSelector(members)
382
+ );
383
+ };
384
+ var expectedUnion = (ast) => `Expected ${unionExpectation(ast)}`;
385
+ var expectedValue = (ast) => {
386
+ const encoded = SchemaAST_exports.toEncoded(ast);
387
+ const values = fixedValues(encoded);
388
+ if (values !== void 0) return allowedValues(values);
389
+ const members = unionMembers(encoded);
390
+ const [only] = members;
391
+ if (only === void 0) return void 0;
392
+ if (members.length > 1 && SchemaAST_exports.isUnion(encoded)) return unionExpectation(encoded);
393
+ if (SchemaAST_exports.isObjects(only) && only.propertySignatures.length > 0)
394
+ return nativeObjectShape(only);
395
+ const described = describeMember(only);
396
+ return described === "a value with other constraints" ? void 0 : described;
397
+ };
398
+ var leafHook = (issue) => SchemaIssue_exports.hasInput(issue) ? "Invalid value" : Match_exports.value(issue).pipe(
399
+ Match_exports.tag("InvalidType", ({ ast }) => {
400
+ const values = fixedValues(ast);
401
+ return values !== void 0 ? `Expected ${allowedValues(values)}` : SchemaAST_exports.isObjects(ast) && ast.propertySignatures.length > 0 ? `Expected ${nativeObjectShape(ast)}` : SchemaIssue_exports.defaultLeafHook(issue);
402
+ }),
403
+ Match_exports.orElse(SchemaIssue_exports.defaultLeafHook)
404
+ );
288
405
  var checkHook = (issue) => SchemaIssue_exports.hasInput(issue) || SchemaIssue_exports.hasInput(issue.issue) ? SchemaIssue_exports.defaultCheckHook(issue) ?? "Invalid value" : SchemaIssue_exports.defaultCheckHook(issue);
289
406
  var format = SchemaIssue_exports.makeFormatterStandardSchemaV1({ leafHook, checkHook });
290
- var segment = (key) => typeof key === "number" ? `[${key}]` : typeof key === "string" && /^[A-Za-z_$][\w$-]{0,63}$/.test(key) ? `.${key}` : "[key]";
291
- var inputInvalid = (error) => {
407
+ var declaredKey = (parent, key) => parent !== void 0 && SchemaAST_exports.isObjects(parent) ? parent.propertySignatures.find(({ name }) => name === key)?.type : void 0;
408
+ var nativeKeys = (parent) => (key) => parent.indexSignatures.length > 0 || parent.propertySignatures.some(({ name }) => name === key);
409
+ var located = (issue, path, parent) => Match_exports.value(issue).pipe(
410
+ Match_exports.tag("Pointer", (pointer) => {
411
+ const declared = pointer.issue._tag === "MissingKey" && pointer.path.length === 1 ? declaredKey(parent, pointer.path[0]) : void 0;
412
+ return declared === void 0 || parent === void 0 || !SchemaAST_exports.isObjects(parent) ? located(pointer.issue, [...path, ...pointer.path]) : [
413
+ {
414
+ path: [...path, ...pointer.path],
415
+ message: missingKey(expectedValue(declared)),
416
+ accepts: nativeKeys(parent)
417
+ }
418
+ ];
419
+ }),
420
+ Match_exports.tag(
421
+ "Composite",
422
+ ({ ast, issues }) => issues.flatMap((issue2) => located(issue2, path, ast))
423
+ ),
424
+ Match_exports.tag("Encoding", (encoding) => located(encoding.issue, path)),
425
+ Match_exports.tag(
426
+ "AnyOf",
427
+ ({ ast, issues }) => issues.length === 0 ? [{ path, message: expectedUnion(ast) }] : issues.flatMap((issue2) => located(issue2, path))
428
+ ),
429
+ Match_exports.orElse((issue2) => {
430
+ const accepts = issue2._tag === "Filter" ? importedSchemaKeys(issue2.filter) : void 0;
431
+ return format(issue2).issues.map((problem) => ({
432
+ path: [
433
+ ...path,
434
+ ...(problem.path ?? []).map((key) => typeof key === "object" ? key.key : key)
435
+ ],
436
+ message: problem.message,
437
+ ...accepts === void 0 ? {} : { accepts }
438
+ }));
439
+ })
440
+ );
441
+ var segment = (key) => typeof key === "number" ? `[${key}]` : typeof key === "string" && echoableKey(key) ? `.${key}` : "[key]";
442
+ var rendered = (path) => `input${path.map(segment).join("")}`;
443
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
444
+ var valueAt = (input, path) => path.reduce(
445
+ (value, key) => Array.isArray(value) && typeof key === "number" ? value[key] : isRecord(value) && typeof key === "string" && Object.hasOwn(value, key) ? value[key] : void 0,
446
+ input
447
+ );
448
+ var spelling = (key) => key.toLowerCase().replace(/[-_]/g, "");
449
+ var suppliedElsewhere = (input, path, accepts) => {
450
+ const key = path.at(-1);
451
+ if (typeof key !== "string" || !echoableKey(key)) return void 0;
452
+ const at = path.slice(0, -1);
453
+ const holder = valueAt(input, at);
454
+ if (!isRecord(holder)) return void 0;
455
+ const candidates = Object.keys(holder).filter((name) => echoableKey(name) && !accepts(name));
456
+ const respelled = candidates.find((name) => name !== key && spelling(name) === spelling(key));
457
+ const deeper = candidates.find((name) => {
458
+ const child = holder[name];
459
+ return isRecord(child) && Object.hasOwn(child, key);
460
+ });
461
+ const found = respelled !== void 0 ? [...at, respelled] : deeper !== void 0 ? [...at, deeper, key] : void 0;
462
+ return found === void 0 ? void 0 : `The input has ${String(found.at(-1))} at ${rendered(found)}; did you mean ${rendered(path)}?`;
463
+ };
464
+ var inputInvalid = (error, input) => {
292
465
  if (!Schema_exports.isSchemaError(error)) return new HostInputInvalid();
293
- const problems = format(error.issue).issues.slice(0, maxInputProblems).map(({ path, message }) => {
294
- const location = (path ?? []).map((key) => segment(typeof key === "object" ? key.key : key));
295
- return `${location.length === 0 ? "input" : `input${location.join("")}`}: ${message}`.slice(
466
+ const problems = located(error.issue, []).slice(0, maxInputProblems).map(({ path, message, accepts }) => {
467
+ const elsewhere = accepts !== void 0 && message.startsWith(missingKeyText) ? suppliedElsewhere(input, path, accepts) : void 0;
468
+ return `${rendered(path)}: ${message}${elsewhere === void 0 ? "" : `. ${elsewhere}`}`.slice(
296
469
  0,
297
470
  512
298
471
  );
@@ -399,7 +572,7 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
399
572
  yield* invoke(hook.unregister, { ...input, state });
400
573
  return null;
401
574
  }
402
- const body = yield* Effect_exports.fromResult(Encoding_exports.decodeBase64(command.request.body)).pipe(
575
+ const body = yield* Effect_exports.fromResult(Base64_exports.decode(command.request.body)).pipe(
403
576
  Effect_exports.mapError(() => new HostInputInvalid())
404
577
  );
405
578
  if (body.byteLength > defaultWebhookTransportLimits.maxBodyBytes)
@@ -448,12 +621,339 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
448
621
  () => Schema_exports.decodeUnknownEffect(WebhookResponseData)({
449
622
  status: response.status,
450
623
  headers,
451
- body: Encoding_exports.encodeBase64(new Uint8Array(bytes))
624
+ body: Base64_exports.encode(new Uint8Array(bytes))
452
625
  }),
453
626
  new HostOutputInvalid()
454
627
  );
455
628
  });
456
629
 
630
+ // src/implementation/sql.ts
631
+ var receipts = `${reservedTablePrefix}step_receipts`;
632
+ var migrationsTable = `${reservedTablePrefix}migrations`;
633
+ var legacyRows = `${reservedTablePrefix}legacy_rows`;
634
+ var materialize = (cursor) => {
635
+ const rows = cursor.toArray();
636
+ return {
637
+ columnNames: cursor.columnNames,
638
+ rowsRead: cursor.rowsRead,
639
+ rowsWritten: cursor.rowsWritten,
640
+ toArray: () => [...rows],
641
+ one: () => {
642
+ if (rows.length !== 1)
643
+ throw new Error(`Expected exactly one row, but the statement returned ${rows.length}.`);
644
+ return rows[0];
645
+ },
646
+ [Symbol.iterator]: () => rows[Symbol.iterator]()
647
+ };
648
+ };
649
+ var isThenable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
650
+ var missingDatabase = () => {
651
+ throw new Error(
652
+ `This app has no database. Add its first migration, such as ${migrationsDirectory}/0001_create_notes.sql with a CREATE TABLE statement, and deploy again.`
653
+ );
654
+ };
655
+ var noDatabase = { exec: missingDatabase, transaction: missingDatabase };
656
+ var settings = [
657
+ "foreign_keys",
658
+ "defer_foreign_keys",
659
+ "ignore_check_constraints",
660
+ "legacy_alter_table",
661
+ "recursive_triggers",
662
+ "reverse_unordered_selects"
663
+ ];
664
+ var readSettings = (storage) => new Map(
665
+ settings.map((name) => [name, Number(storage.sql.exec(`PRAGMA ${name}`).toArray()[0]?.[name])])
666
+ );
667
+ var changedSetting = (storage, baseline) => {
668
+ const current = readSettings(storage);
669
+ return settings.find((name) => current.get(name) !== baseline.get(name));
670
+ };
671
+ var restoreSettings = (storage, baseline) => {
672
+ const current = readSettings(storage);
673
+ for (const [name, value] of baseline)
674
+ if (current.get(name) !== value) storage.sql.exec(`PRAGMA ${name} = ${value}`);
675
+ storage.sql.exec("PRAGMA case_sensitive_like = OFF");
676
+ };
677
+ var ReadRolledBack = class extends Error {
678
+ };
679
+ var authorSql = (storage, options) => {
680
+ let closed = false;
681
+ const live = () => {
682
+ if (closed || options.signal.aborted)
683
+ throw new Error("This call has ended, so its ctx.sql no longer runs statements.");
684
+ };
685
+ let open = false;
686
+ let transactions = 0;
687
+ const baseline = readSettings(storage);
688
+ const checkSettings = () => {
689
+ const changed = changedSetting(storage, baseline);
690
+ if (changed !== void 0)
691
+ throw refuse(
692
+ new Error(
693
+ `SQLite connection settings belong to Executor, so app code cannot change PRAGMA ${changed}; the statement was rolled back. Migrations may change settings while they run.`
694
+ )
695
+ );
696
+ };
697
+ const changes = () => Number(storage.sql.exec("SELECT total_changes() AS n").toArray()[0]?.n);
698
+ let violation;
699
+ const refuse = (error) => {
700
+ if (open) violation ??= error;
701
+ return error;
702
+ };
703
+ const run = (query, bindings, mode) => {
704
+ try {
705
+ return runStatement(query, bindings, mode);
706
+ } finally {
707
+ restoreSettings(storage, baseline);
708
+ }
709
+ };
710
+ const runStatement = (query, bindings, mode) => {
711
+ live();
712
+ if (mode === "write") {
713
+ const statement = () => {
714
+ const cursor = materialize(storage.sql.exec(query, ...bindings));
715
+ checkSettings();
716
+ return cursor;
717
+ };
718
+ if (!open) return storage.transactionSync(statement);
719
+ try {
720
+ return statement();
721
+ } catch (error) {
722
+ refuse(error instanceof Error ? error : new Error(String(error)));
723
+ throw error;
724
+ }
725
+ }
726
+ if (open) {
727
+ return runStatement(query, bindings, "write");
728
+ }
729
+ const before = changes();
730
+ let read;
731
+ let changed = false;
732
+ try {
733
+ storage.transactionSync(() => {
734
+ read = materialize(storage.sql.exec(query, ...bindings));
735
+ changed = changes() !== before;
736
+ checkSettings();
737
+ throw new ReadRolledBack();
738
+ });
739
+ } catch (error) {
740
+ if (!(error instanceof ReadRolledBack)) throw error;
741
+ }
742
+ if (changed || read === void 0)
743
+ throw new Error(
744
+ options.step !== void 0 ? "A workflow step mutation writes only inside ctx.sql.transaction(...), so a retried step applies its writes once." : "Queries are read-only. Change data from a mutation."
745
+ );
746
+ return read;
747
+ };
748
+ const reader = {
749
+ exec: (query, ...bindings) => run(query, bindings, "read")
750
+ };
751
+ const transactionHandle = () => {
752
+ let active = true;
753
+ const tx = {
754
+ exec: (query, ...bindings) => {
755
+ if (!active)
756
+ throw new Error("This transaction has ended, so its tx no longer runs statements.");
757
+ return run(query, bindings, "write");
758
+ }
759
+ };
760
+ return {
761
+ tx,
762
+ end: () => {
763
+ active = false;
764
+ }
765
+ };
766
+ };
767
+ const transaction = (work) => {
768
+ live();
769
+ if (open) throw new Error("ctx.sql.transaction(...) cannot be nested.");
770
+ const step = options.step;
771
+ if (step !== void 0 && transactions > 0)
772
+ throw new Error(
773
+ "A workflow step mutation opens at most one ctx.sql.transaction(...), which records the step's result."
774
+ );
775
+ transactions += 1;
776
+ violation = void 0;
777
+ const handle = transactionHandle();
778
+ return storage.transactionSync(() => {
779
+ open = true;
780
+ try {
781
+ const complete = () => {
782
+ const value = work(handle.tx);
783
+ if (isThenable(value))
784
+ throw new Error(
785
+ "ctx.sql.transaction(...) callbacks are synchronous and cannot await. Call outside services before or after the transaction."
786
+ );
787
+ if (violation !== void 0) throw violation;
788
+ return value;
789
+ };
790
+ if (step === void 0) return complete();
791
+ storage.sql.exec(
792
+ `CREATE TABLE IF NOT EXISTS ${receipts} (id TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, result TEXT NOT NULL) WITHOUT ROWID`
793
+ );
794
+ const saved = storage.sql.exec(`SELECT fingerprint, result FROM ${receipts} WHERE id = ?`, step.key).toArray()[0];
795
+ if (saved !== void 0) {
796
+ if (saved.fingerprint !== step.fingerprint)
797
+ throw new Error("This workflow step already ran with different input.");
798
+ return JSON.parse(String(saved.result));
799
+ }
800
+ const encoded = JSON.stringify(complete() ?? null);
801
+ storage.sql.exec(
802
+ `INSERT INTO ${receipts} (id, fingerprint, result) VALUES (?, ?, ?)`,
803
+ step.key,
804
+ step.fingerprint,
805
+ encoded
806
+ );
807
+ return JSON.parse(encoded);
808
+ } finally {
809
+ open = false;
810
+ handle.end();
811
+ }
812
+ });
813
+ };
814
+ const writer = {
815
+ // A step's writes go through its one transaction, which also records its receipt.
816
+ exec: (query, ...bindings) => run(query, bindings, options.step ? "read" : "write"),
817
+ transaction
818
+ };
819
+ return {
820
+ reader,
821
+ writer,
822
+ close: () => {
823
+ closed = true;
824
+ }
825
+ };
826
+ };
827
+ var MigrationFileInvalid = class extends Schema_exports.TaggedError()(
828
+ "MigrationFileInvalid",
829
+ { path: Schema_exports.String, reason: Schema_exports.String }
830
+ ) {
831
+ get message() {
832
+ return `${this.path}: ${this.reason}`;
833
+ }
834
+ };
835
+ var MigrationHistoryChanged = class extends Schema_exports.TaggedError()(
836
+ "MigrationHistoryChanged",
837
+ { reason: Schema_exports.String }
838
+ ) {
839
+ get message() {
840
+ return `${this.reason} Applied migrations cannot change: restore the original file and add a new migration instead. Nothing was applied; the previous deployment is still active.`;
841
+ }
842
+ };
843
+ var MigrationFailed = class extends Schema_exports.TaggedError()("MigrationFailed", {
844
+ path: Schema_exports.String,
845
+ reason: Schema_exports.String
846
+ }) {
847
+ get message() {
848
+ return `${this.path} failed: ${this.reason}. No migrations were applied; the previous deployment is still active.`;
849
+ }
850
+ };
851
+ var migrationName = /^(\d+)_[A-Za-z0-9_-]+\.sql$/;
852
+ var sha256 = (text) => Effect_exports.promise(() => crypto.subtle.digest("SHA-256", new TextEncoder().encode(text))).pipe(
853
+ Effect_exports.map(
854
+ (digest) => Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")
855
+ )
856
+ );
857
+ var hasMigrations = (files) => files.some(
858
+ (file) => file.path.startsWith(`${migrationsDirectory}/`) && file.path.endsWith(".sql")
859
+ );
860
+ var migrationsOf = (files) => Effect_exports.gen(function* () {
861
+ const found = [];
862
+ for (const file of files) {
863
+ if (!file.path.startsWith(`${migrationsDirectory}/`) || !file.path.endsWith(".sql")) continue;
864
+ const name = file.path.slice(migrationsDirectory.length + 1);
865
+ const match = migrationName.exec(name);
866
+ if (name.includes("/") || match === null)
867
+ return yield* new MigrationFileInvalid({
868
+ path: file.path,
869
+ reason: "migrations are files directly in migrations/ named like 0001_create_notes.sql: a number that orders them, an underscore, then a name."
870
+ });
871
+ const content = file.content.replaceAll("\r\n", "\n");
872
+ found.push({
873
+ path: file.path,
874
+ order: Number(match[1]),
875
+ content,
876
+ hash: yield* sha256(content)
877
+ });
878
+ }
879
+ const ordered = [...found].sort((left, right) => left.order - right.order);
880
+ for (const [index, migration] of ordered.entries()) {
881
+ const previous = ordered[index - 1];
882
+ if (previous !== void 0 && previous.order === migration.order)
883
+ return yield* new MigrationFileInvalid({
884
+ path: migration.path,
885
+ reason: `it has the same number as ${previous.path}; give each migration its own number.`
886
+ });
887
+ }
888
+ return ordered;
889
+ });
890
+ var History = Schema_exports.Array(
891
+ Schema_exports.Struct({ id: Schema_exports.Number, path: Schema_exports.String, hash: Schema_exports.String })
892
+ );
893
+ var migrate = (storage, files) => Effect_exports.gen(function* () {
894
+ const migrations = yield* migrationsOf(files);
895
+ const baseline = readSettings(storage);
896
+ return yield* Effect_exports.sync(
897
+ () => storage.transactionSync(() => {
898
+ storage.sql.exec(
899
+ `CREATE TABLE IF NOT EXISTS ${migrationsTable} (id INTEGER PRIMARY KEY, path TEXT NOT NULL, hash TEXT NOT NULL, applied_at TEXT NOT NULL)`
900
+ );
901
+ const stored = storage.sql.exec("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'app_rows'").toArray().length > 0;
902
+ storage.sql.exec(`DROP VIEW IF EXISTS ${legacyRows}`);
903
+ storage.sql.exec(
904
+ `CREATE VIEW ${legacyRows} (table_name, id, body) AS ${stored ? "SELECT table_name, id, body FROM app_rows" : "SELECT '', '', '' WHERE 0"}`
905
+ );
906
+ const history = Schema_exports.decodeUnknownSync(History)(
907
+ storage.sql.exec(`SELECT id, path, hash FROM ${migrationsTable} ORDER BY id`).toArray()
908
+ );
909
+ for (const [index, applied] of history.entries()) {
910
+ const current = migrations[index];
911
+ if (current === void 0)
912
+ throw new MigrationHistoryChanged({
913
+ reason: `${applied.path} was applied to this app's database but is no longer in migrations/.`
914
+ });
915
+ if (current.path !== applied.path)
916
+ throw new MigrationHistoryChanged({
917
+ reason: `Migration ${index + 1} was applied as ${applied.path}, but the build has ${current.path} in its place.`
918
+ });
919
+ if (current.hash !== applied.hash)
920
+ throw new MigrationHistoryChanged({
921
+ reason: `${applied.path} changed after it was applied to this app's database.`
922
+ });
923
+ }
924
+ const pending = migrations.slice(history.length);
925
+ const appliedAt = (/* @__PURE__ */ new Date()).toISOString();
926
+ for (const [offset, migration] of pending.entries()) {
927
+ try {
928
+ storage.sql.exec(migration.content);
929
+ } catch (error) {
930
+ throw new MigrationFailed({
931
+ path: migration.path,
932
+ reason: error instanceof Error ? error.message : String(error)
933
+ });
934
+ }
935
+ storage.sql.exec(
936
+ `INSERT INTO ${migrationsTable} (id, path, hash, applied_at) VALUES (?, ?, ?, ?)`,
937
+ history.length + offset + 1,
938
+ migration.path,
939
+ migration.hash,
940
+ appliedAt
941
+ );
942
+ }
943
+ return pending.map((migration, offset) => ({
944
+ id: history.length + offset + 1,
945
+ name: migration.path
946
+ }));
947
+ })
948
+ ).pipe(
949
+ // Both are thrown inside the transaction so that it rolls back; they are expected failures.
950
+ Effect_exports.catchDefect(
951
+ (defect) => Schema_exports.is(MigrationFailed)(defect) || Schema_exports.is(MigrationHistoryChanged)(defect) ? Effect_exports.fail(defect) : Effect_exports.die(defect)
952
+ ),
953
+ Effect_exports.ensuring(Effect_exports.sync(() => restoreSettings(storage, baseline)))
954
+ );
955
+ });
956
+
457
957
  // src/implementation/cache.ts
458
958
  var unavailableCache = {
459
959
  transport: () => Effect_exports.fail(new CacheError({ reason: "unavailable" })),
@@ -469,7 +969,7 @@ var authorCache = (host, accounts, signal, deadline) => {
469
969
  ...options.staleFor === void 0 ? {} : { staleFor: options.staleFor },
470
970
  load: Effect_exports.acquireUseRelease(
471
971
  Effect_exports.sync(() => new AbortController()),
472
- (controller) => invocationFetch(controller.signal).pipe(
972
+ (controller) => appInvocationFetch(controller.signal).pipe(
473
973
  Effect_exports.flatMap(
474
974
  (fetch) => fromPromise(options.load)({
475
975
  fetch,
@@ -523,6 +1023,10 @@ var authorCache = (host, accounts, signal, deadline) => {
523
1023
  };
524
1024
 
525
1025
  // src/implementation/host.ts
1026
+ var WireCatalog = Schema_exports.Struct({
1027
+ tools: Schema_exports.Array(Schema_exports.Union([HostedTool, HostedToolSummary])),
1028
+ routers: Schema_exports.Array(HostedRouter)
1029
+ });
526
1030
  function safe2(work, failure) {
527
1031
  return Effect_exports.suspend(work).pipe(
528
1032
  Effect_exports.catchCause(
@@ -530,30 +1034,39 @@ function safe2(work, failure) {
530
1034
  )
531
1035
  );
532
1036
  }
533
- var evaluationSafe = (work) => work.pipe(
1037
+ var evaluationSafe = (work, secrets) => work.pipe(
534
1038
  Effect_exports.catchCause((cause) => {
535
1039
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
536
1040
  const error = Cause_exports.squash(cause);
537
1041
  const provider = parseProviderError(error);
538
1042
  const skills = parseSkillLoadFailed(error);
539
- const mcp = parseMcpError(error);
1043
+ const mcp = parseMcpError(error, secrets);
540
1044
  return Effect_exports.fail(
541
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed()
1045
+ Option_exports.isSome(provider) ? leavingProviderError(provider.value, secrets, "discover") : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed(failureDetail(error, secrets))
542
1046
  );
543
1047
  })
544
1048
  );
545
- function jsonSchema(decoder) {
546
- const imported = importedJsonSchema(decoder);
547
- if (imported !== void 0) return Schema_exports.decodeUnknownEffect(JsonObject)(imported);
548
- const document = Schema_exports.toJsonSchemaDocument(decoder);
549
- return Schema_exports.decodeUnknownEffect(JsonObject)({
550
- ...document.schema,
551
- $defs: document.definitions,
552
- $schema: "https://json-schema.org/draft/2020-12/schema"
553
- });
1049
+ var declarationInvalid = (summary, cause, secrets = []) => new HostDeclarationInvalid({
1050
+ source: "app",
1051
+ errorName: "HostDeclarationInvalid",
1052
+ message: boundFailureMessage(
1053
+ cause === void 0 ? summary : `${summary}: ${describeFailure(cause)}`,
1054
+ secrets
1055
+ )
1056
+ });
1057
+ var declarationSafe = (work, summary) => Effect_exports.suspend(work).pipe(
1058
+ Effect_exports.catchCause(
1059
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(declarationInvalid(summary, Cause_exports.squash(cause)))
1060
+ )
1061
+ );
1062
+ function declaredExposure(exposure) {
1063
+ const named = (kind) => Object.entries(exposure ?? {}).filter(([, value]) => value === kind).map(([field]) => field).sort();
1064
+ const plain = named("plain");
1065
+ const raw = named("raw");
1066
+ return { ...plain.length === 0 ? {} : { plain }, ...raw.length === 0 ? {} : { raw } };
554
1067
  }
555
1068
  function providerDeclaration(provider) {
556
- return safe2(
1069
+ return declarationSafe(
557
1070
  () => Effect_exports.gen(function* () {
558
1071
  const auth = /* @__PURE__ */ new Map();
559
1072
  for (const [name, method] of Object.entries(provider.auth)) {
@@ -562,42 +1075,50 @@ function providerDeclaration(provider) {
562
1075
  auth.set(name, {
563
1076
  type: "secrets",
564
1077
  label: method.label,
565
- fields: yield* jsonSchema(method.fields)
1078
+ fields: yield* jsonSchemaDocument(method.fields),
1079
+ ...declaredExposure(method.exposure)
566
1080
  });
567
1081
  break;
568
1082
  case "oauth2":
569
1083
  auth.set(name, {
570
1084
  type: "oauth2",
571
1085
  ...method.config,
572
- response: yield* jsonSchema(method.response)
1086
+ response: yield* jsonSchemaDocument(method.response),
1087
+ ...declaredExposure(method.exposure)
573
1088
  });
574
1089
  break;
575
1090
  }
576
1091
  }
577
1092
  return yield* Schema_exports.decodeUnknownEffect(DeclaredProvider)({
578
1093
  name: provider.name,
579
- auth: Object.fromEntries(auth)
1094
+ auth: Object.fromEntries(auth),
1095
+ // Order and repetition carry no meaning, so neither changes the provider's identity.
1096
+ ...provider.hosts === void 0 ? {} : { hosts: [...new Set(provider.hosts)].sort() }
580
1097
  });
581
1098
  }),
582
- new HostDeclarationInvalid()
1099
+ `Account provider "${provider.name}" has an invalid declaration`
583
1100
  );
584
1101
  }
585
- function requirements(slots, database) {
1102
+ function requirements(slots, sql) {
586
1103
  return Effect_exports.gen(function* () {
587
1104
  const accounts = /* @__PURE__ */ new Map();
588
1105
  for (const [slot, selection] of Object.entries(slots)) {
1106
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
589
1107
  accounts.set(slot, {
590
1108
  cardinality: selection instanceof ManyAccounts ? "many" : "one",
591
- definition: yield* providerDeclaration(
592
- selection instanceof ManyAccounts ? selection.provider : selection
593
- )
1109
+ definition: yield* providerDeclaration(provider),
1110
+ ...provider.health === void 0 ? {} : { health: true }
594
1111
  });
595
1112
  }
596
1113
  return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
597
1114
  accounts: Object.fromEntries(accounts),
598
1115
  capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
599
- ...database === void 0 ? {} : { database }
600
- }).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1116
+ ...sql ? { sql: true } : {}
1117
+ }).pipe(
1118
+ Effect_exports.mapError(
1119
+ (cause) => declarationInvalid("The app's account declarations are invalid", cause)
1120
+ )
1121
+ );
601
1122
  });
602
1123
  }
603
1124
  function canonical(value) {
@@ -607,6 +1128,9 @@ function canonical(value) {
607
1128
  }
608
1129
  return JSON.stringify(value);
609
1130
  }
1131
+ function withoutHosts({ hosts: _hosts, ...provider }) {
1132
+ return provider;
1133
+ }
610
1134
  function bindAccounts(slots, declarations, context) {
611
1135
  return safe2(
612
1136
  () => Effect_exports.gen(function* () {
@@ -632,7 +1156,7 @@ function bindAccounts(slots, declarations, context) {
632
1156
  for (const account of accounts) {
633
1157
  if (ids.has(account.id)) return yield* Effect_exports.fail(new HostAccountsInvalid());
634
1158
  ids.add(account.id);
635
- if (canonical(account.provider) !== canonical(requirement.definition) || !Object.hasOwn(provider.auth, account.method))
1159
+ if (canonical(withoutHosts(account.provider)) !== canonical(withoutHosts(requirement.definition)) || !Object.hasOwn(provider.auth, account.method))
636
1160
  return yield* Effect_exports.fail(new HostAccountsInvalid());
637
1161
  const method = provider.auth[account.method];
638
1162
  if (method === void 0) return yield* Effect_exports.fail(new HostAccountsInvalid());
@@ -653,22 +1177,95 @@ function bindAccounts(slots, declarations, context) {
653
1177
  new HostAccountsInvalid()
654
1178
  );
655
1179
  }
1180
+ var fetchLifetime = (signal, background) => Effect_exports.acquireRelease(
1181
+ Effect_exports.sync(() => {
1182
+ const controller = new AbortController();
1183
+ let refreshes = 0;
1184
+ let ended = false;
1185
+ const settle = () => {
1186
+ if (ended && refreshes === 0) controller.abort();
1187
+ };
1188
+ const end = () => {
1189
+ ended = true;
1190
+ settle();
1191
+ };
1192
+ signal.addEventListener("abort", end, { once: true });
1193
+ if (signal.aborted) end();
1194
+ const settled = Effect_exports.sync(() => {
1195
+ refreshes -= 1;
1196
+ settle();
1197
+ });
1198
+ return {
1199
+ signal: controller.signal,
1200
+ close: () => {
1201
+ signal.removeEventListener("abort", end);
1202
+ end();
1203
+ },
1204
+ /** Counted from the hand-off, so a refresh that has not started yet keeps the fetch. */
1205
+ background: (task) => Effect_exports.suspend(() => {
1206
+ refreshes += 1;
1207
+ return background(task.pipe(Effect_exports.ensuring(settled))).pipe(
1208
+ Effect_exports.onError(() => settled)
1209
+ );
1210
+ })
1211
+ };
1212
+ }),
1213
+ (lifetime) => Effect_exports.sync(lifetime.close)
1214
+ );
656
1215
  function dispatch(app, request, context, signal) {
657
1216
  return Effect_exports.scoped(
658
1217
  Effect_exports.gen(function* () {
659
- if (!isApp(app)) return yield* Effect_exports.fail(new HostDeclarationInvalid());
1218
+ if (!isApp(app))
1219
+ return yield* Effect_exports.fail(
1220
+ declarationInvalid("The app module's default export is not an app created by defineApp")
1221
+ );
660
1222
  const native = toEffectApp(app);
661
- const declared = yield* requirements(native.accounts, native.database?.schema);
1223
+ const secrets = accountSecrets(context.accounts);
1224
+ const ownsSql = hasMigrations(context.files ?? []);
1225
+ const declared = yield* requirements(native.accounts, ownsSql);
662
1226
  if (request.operation === "requirements")
663
1227
  return yield* safe2(
664
1228
  () => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
665
1229
  new HostDeclarationInvalid()
666
1230
  );
1231
+ if (request.operation === "migrate") {
1232
+ if (!ownsSql) return yield* new HostOperationNotFound();
1233
+ const storage2 = context.storage;
1234
+ if (storage2 === void 0)
1235
+ return yield* new HostOperationFailed(
1236
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1237
+ );
1238
+ const sources = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(SkillFile))(
1239
+ context.files ?? []
1240
+ ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1241
+ const applied = yield* migrate(storage2, sources).pipe(
1242
+ Effect_exports.mapError((error) => new HostOperationFailed(failureDetail(error, secrets))),
1243
+ Effect_exports.withSpan("app.sql.migrate")
1244
+ );
1245
+ return yield* safe2(
1246
+ () => Schema_exports.decodeUnknownEffect(JsonValue)(applied),
1247
+ new HostOutputInvalid()
1248
+ );
1249
+ }
667
1250
  const lifetime = yield* Effect_exports.acquireRelease(
668
1251
  Effect_exports.sync(() => new AbortController()),
669
1252
  (controller) => Effect_exports.sync(() => controller.abort())
670
1253
  );
671
1254
  const invocationSignal = AbortSignal.any([signal, lifetime.signal]);
1255
+ const storage = context.storage;
1256
+ const sqlSession = (step) => !ownsSql ? Effect_exports.succeed({ reader: noDatabase, writer: noDatabase }) : storage === void 0 ? Effect_exports.fail(
1257
+ new HostOperationFailed(
1258
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1259
+ )
1260
+ ) : Effect_exports.acquireRelease(
1261
+ Effect_exports.sync(
1262
+ () => authorSql(storage, {
1263
+ signal: invocationSignal,
1264
+ ...step === void 0 ? {} : { step }
1265
+ })
1266
+ ),
1267
+ (session2) => Effect_exports.sync(session2.close)
1268
+ );
672
1269
  const deadline = context.deadline === void 0 ? void 0 : yield* safe2(
673
1270
  () => Schema_exports.decodeUnknownEffect(InvocationDeadline)(context.deadline),
674
1271
  new HostInputInvalid()
@@ -689,10 +1286,18 @@ function dispatch(app, request, context, signal) {
689
1286
  return yield* new WorkflowFailure({ reason: "engine", retryable: true });
690
1287
  return result;
691
1288
  });
1289
+ if (request.operation === "account-check")
1290
+ return yield* checkAccount(
1291
+ native.accounts,
1292
+ declared,
1293
+ request.requirement,
1294
+ context,
1295
+ invocationSignal,
1296
+ deadline
1297
+ ).pipe(withinDeadline);
692
1298
  let running;
693
- let transactionOpen = false;
694
1299
  const delivery = (request2, signal2) => Effect_exports.suspend(
695
- () => transactionOpen ? Effect_exports.fail(new ElicitationFailed({ reason: "transaction" })) : running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
1300
+ () => running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
696
1301
  Effect_exports.withSpan("app.tool.elicitation"),
697
1302
  Effect_exports.provideContext(running.context)
698
1303
  ) : Effect_exports.fail(new ElicitationFailed({ reason: "unavailable" }))
@@ -725,6 +1330,7 @@ function dispatch(app, request, context, signal) {
725
1330
  ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
726
1331
  let cacheCommands = 0;
727
1332
  const hostCache = context.cache ?? unavailableCache;
1333
+ const fetching = yield* fetchLifetime(signal, hostCache.background);
728
1334
  const bound = {
729
1335
  cache: authorCache(
730
1336
  {
@@ -732,7 +1338,8 @@ function dispatch(app, request, context, signal) {
732
1338
  transport: (command) => {
733
1339
  cacheCommands += 1;
734
1340
  return hostCache.transport(command);
735
- }
1341
+ },
1342
+ background: fetching.background
736
1343
  },
737
1344
  Redacted_exports.value(context.accounts),
738
1345
  invocationSignal,
@@ -744,37 +1351,43 @@ function dispatch(app, request, context, signal) {
744
1351
  ),
745
1352
  workflows: workflowReads,
746
1353
  signal: invocationSignal,
747
- fetch: yield* invocationFetch(invocationSignal),
1354
+ fetch: yield* appInvocationFetch(fetching.signal),
748
1355
  elicit: makeElicit(delivery, invocationSignal)
749
1356
  };
750
- const definition = yield* evaluationSafe(native.evaluate(bound)).pipe(
1357
+ const definition = yield* evaluationSafe(native.evaluate(bound), secrets).pipe(
751
1358
  Effect_exports.withSpan("app.evaluate")
752
1359
  );
753
1360
  if (request.operation === "skills") {
754
1361
  const declared2 = definition.skills ?? (yield* folderSkillsEffect({ files }).pipe(
755
1362
  Effect_exports.mapError(() => new HostDeclarationInvalid())
756
1363
  ));
757
- const source2 = definition.dynamicSkills;
1364
+ const source = definition.dynamicSkills;
758
1365
  const before = cacheCommands;
759
- const dynamic = source2 === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source2.list)).pipe(
1366
+ const dynamic = source === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source.list), secrets).pipe(
760
1367
  Effect_exports.withSpan("app.skills.load")
761
1368
  );
762
- const cached = source2 !== void 0 && cacheCommands > before;
763
- const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([...declared2, ...dynamic]).pipe(
764
- Effect_exports.mapError(() => new HostDeclarationInvalid())
765
- );
766
- return request.sources === true ? { skills, dynamic: source2 !== void 0, cached } : skills;
1369
+ const cached = source !== void 0 && cacheCommands > before;
1370
+ const authored = new Set([...declared2, ...dynamic].map((skill) => skill.name));
1371
+ const routed = (yield* routerSkills(definition.tools).pipe(
1372
+ Effect_exports.withSpan("app.skills.routers")
1373
+ )).filter((skill) => !authored.has(skill.name));
1374
+ const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([
1375
+ ...declared2,
1376
+ ...dynamic,
1377
+ ...routed
1378
+ ]).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1379
+ return request.sources === true ? { skills, dynamic: source !== void 0, cached } : skills;
767
1380
  }
768
1381
  if (request.operation === "workflows") {
769
1382
  return yield* Effect_exports.forEach(
770
1383
  Object.entries(definition.workflows ?? {}),
771
- ([name2, entry]) => safe2(
1384
+ ([name, entry]) => safe2(
772
1385
  () => Effect_exports.gen(function* () {
773
1386
  return yield* Schema_exports.decodeUnknownEffect(HostedWorkflow)({
774
- name: name2,
1387
+ name,
775
1388
  ...entry.description === void 0 ? {} : { description: entry.description },
776
- inputSchema: yield* jsonSchema(entry.input),
777
- ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchema(entry.output) }
1389
+ inputSchema: yield* jsonSchemaDocument(entry.input),
1390
+ ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchemaDocument(entry.output) }
778
1391
  });
779
1392
  }),
780
1393
  new HostDeclarationInvalid()
@@ -807,111 +1420,64 @@ function dispatch(app, request, context, signal) {
807
1420
  new WorkflowFailure({ reason: "credentials", retryable: false })
808
1421
  );
809
1422
  return {
810
- ...accounts,
811
- cache: authorCache(
812
- context.cache ?? unavailableCache,
813
- Redacted_exports.value(current.accounts),
814
- signal2
815
- ),
816
- files,
817
- fetch: yield* invocationFetch(signal2),
818
- signal: signal2,
819
- runId: execution.runId,
820
- stepId,
821
- idempotencyKey: stepId
1423
+ context: {
1424
+ ...accounts,
1425
+ cache: authorCache(
1426
+ context.cache ?? unavailableCache,
1427
+ Redacted_exports.value(current.accounts),
1428
+ signal2
1429
+ ),
1430
+ files,
1431
+ fetch: yield* appInvocationFetch(signal2),
1432
+ signal: signal2,
1433
+ runId: execution.runId,
1434
+ stepId,
1435
+ idempotencyKey: stepId
1436
+ },
1437
+ // The resolved values, not the app's decoded fields, which may be `Redacted`.
1438
+ secrets: accountSecrets(current.accounts)
822
1439
  };
823
1440
  }),
824
1441
  invocationSignal
825
1442
  );
826
- const output = yield* workflowSafe(entry.run(workflowContext, input2));
1443
+ const output = yield* workflowSafe(entry.run(workflowContext, input2), secrets);
827
1444
  const outputSchema = entry.output;
828
1445
  const decoded = outputSchema === void 0 ? output : yield* safe2(
829
1446
  () => Schema_exports.decodeUnknownEffect(outputSchema)(output),
830
- new WorkflowFailure({ reason: "output", retryable: false })
1447
+ new WorkflowFailure({
1448
+ reason: "output",
1449
+ retryable: false,
1450
+ message: "The workflow's result does not match its declared output schema."
1451
+ })
831
1452
  );
832
1453
  return yield* safe2(
833
1454
  () => Schema_exports.decodeUnknownEffect(WorkflowValue)(decoded),
834
- new WorkflowFailure({ reason: "output", retryable: false })
1455
+ new WorkflowFailure({
1456
+ reason: "output",
1457
+ retryable: false,
1458
+ message: "The workflow returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
1459
+ })
835
1460
  );
836
1461
  }
837
1462
  if (request.operation === "inspect") {
838
1463
  const summary = request.detail === "summary";
839
- const wanted = request.tools === void 0 ? void 0 : new Set(request.tools);
840
- const metadata = [];
841
- for (const [prefix, readOnly, catalog2] of [
842
- [OperationToolPrefixes.query, true, definition.queries],
843
- [OperationToolPrefixes.mutate, false, definition.mutations]
844
- ]) {
845
- for (const [name2, operation] of Object.entries(catalog2 ?? {})) {
846
- if (wanted !== void 0 && !wanted.has(`${prefix}${name2}`)) continue;
847
- const schedules = Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === `${prefix}${name2}`).map(([name3, { tool: _tool, ...schedule }]) => ({ name: name3, ...schedule }));
848
- if (request.scheduled === true && schedules.length === 0) continue;
849
- metadata.push(
850
- yield* safe2(
851
- () => Effect_exports.gen(function* () {
852
- const fields = {
853
- name: `${prefix}${name2}`,
854
- schedules,
855
- description: operation.description ?? `${readOnly ? "Query" : "Mutate"} ${name2}`,
856
- ...operation.title === void 0 ? {} : { title: operation.title },
857
- readOnly,
858
- annotations: { ...operation.annotations, readOnlyHint: readOnly }
859
- };
860
- if (summary)
861
- return yield* Schema_exports.decodeUnknownEffect(HostedToolSummary)(fields);
862
- return yield* Schema_exports.decodeUnknownEffect(HostedTool)({
863
- ...fields,
864
- inputSchema: yield* jsonSchema(operation.input),
865
- ...operation.output === void 0 ? operation.outputSchema === void 0 ? {} : { outputSchema: operation.outputSchema } : { outputSchema: yield* jsonSchema(operation.output) },
866
- ...operation._meta === void 0 ? {} : { _meta: operation._meta }
867
- });
868
- }),
869
- new HostDeclarationInvalid()
870
- )
871
- );
872
- }
873
- }
874
- const dynamic = request.scheduled === true ? void 0 : definition.dynamicTools;
875
- if (dynamic !== void 0 && (wanted === void 0 || metadata.length < wanted.size)) {
876
- const declared2 = new Set(metadata.map((tool2) => tool2.name));
877
- const discover = () => {
878
- if (summary && dynamic.summaries !== void 0) return dynamic.summaries();
879
- if (wanted !== void 0 && dynamic.describe !== void 0) {
880
- const describe = dynamic.describe;
881
- return Effect_exports.forEach(
882
- [...wanted].filter((name2) => !declared2.has(name2)),
883
- (name2) => describe(name2),
884
- { concurrency: "unbounded" }
885
- ).pipe(Effect_exports.map((tools) => tools.filter((tool2) => tool2 !== void 0)));
886
- }
887
- return dynamic.list();
888
- };
889
- const discovered = yield* evaluationSafe(discover()).pipe(
890
- Effect_exports.flatMap(
891
- (value) => safe2(
892
- () => summary ? Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedToolSummary))(value) : Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedTool))(value),
893
- new HostDeclarationInvalid()
894
- )
895
- )
896
- );
897
- const names = new Set(declared2);
898
- for (const tool2 of discovered) {
899
- const readOnly = tool2.name.startsWith(OperationToolPrefixes.query);
900
- if (!readOnly && !tool2.name.startsWith(OperationToolPrefixes.mutate) || tool2.name === OperationToolPrefixes.query || tool2.name === OperationToolPrefixes.mutate || names.has(tool2.name))
901
- return yield* new HostDeclarationInvalid();
902
- names.add(tool2.name);
903
- if (wanted !== void 0 && !wanted.has(tool2.name)) continue;
904
- metadata.push({
905
- ...tool2,
906
- readOnly,
907
- annotations: { ...tool2.annotations, readOnlyHint: readOnly }
908
- });
909
- }
910
- }
911
- return metadata;
1464
+ const catalog = yield* readCatalog(definition.tools, {
1465
+ summary,
1466
+ secrets,
1467
+ ...request.tools === void 0 ? {} : { wanted: new Set(request.tools) },
1468
+ ...request.scheduled === true ? { scheduled: true } : {},
1469
+ schedules: (name) => Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === name).map(([name2, { tool: _tool, ...schedule }]) => ({ name: name2, ...schedule }))
1470
+ }).pipe(Effect_exports.withSpan("app.catalog.read"));
1471
+ return yield* safe2(
1472
+ () => Schema_exports.encodeEffect(WireCatalog)(catalog).pipe(
1473
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
1474
+ ),
1475
+ new HostDeclarationInvalid()
1476
+ );
912
1477
  }
913
1478
  if (request.operation === "webhook-complete" || request.operation === "webhook-validate" || request.operation === "webhooks" || request.operation === "webhook-register" || request.operation === "webhook-handle" || request.operation === "webhook-unregister") {
914
- const executeWebhook = (db) => dispatchWebhook(
1479
+ const session2 = yield* sqlSession();
1480
+ return yield* dispatchWebhook(
915
1481
  definition,
916
1482
  request,
917
1483
  {
@@ -921,41 +1487,25 @@ function dispatch(app, request, context, signal) {
921
1487
  workflows: workflowControls,
922
1488
  signal: bound.signal,
923
1489
  fetch: bound.fetch,
924
- ...db === void 0 || native.database === void 0 ? {} : {
925
- db: authorDatabase(native.database.tables, db, invocationSignal, true)
926
- }
1490
+ sql: session2.writer
927
1491
  },
928
1492
  Redacted_exports.value(context.accounts)
929
1493
  );
930
- if (native.database === void 0 || !["webhook-register", "webhook-handle", "webhook-unregister"].includes(request.operation))
931
- return yield* executeWebhook();
932
- const storage2 = context.storage ?? unavailableStorage;
933
- return yield* storage2.mutate(native.database.schema, executeWebhook).pipe(
934
- Effect_exports.catchTags({
935
- AppDatabaseError: () => Effect_exports.fail(new HostOperationFailed()),
936
- AppStorageUnavailable: () => Effect_exports.fail(new HostOperationFailed()),
937
- AppStorageError: () => Effect_exports.fail(new HostOperationFailed())
938
- })
939
- );
940
1494
  }
941
- const kind = request.operation === "call" ? request.tool.startsWith(OperationToolPrefixes.query) ? "query" : request.tool.startsWith(OperationToolPrefixes.mutate) ? "mutate" : void 0 : request.operation;
942
- if (kind === void 0) return yield* new HostToolNotFound();
943
- const name = request.operation === "call" ? request.tool.slice(OperationToolPrefixes[kind].length) : request.name;
944
- const toolName = `${OperationToolPrefixes[kind]}${name}`;
945
- const catalog = kind === "query" ? definition.queries : definition.mutations;
946
- const declaredTool = catalog !== void 0 && Object.hasOwn(catalog, name) ? catalog[name] : void 0;
947
- const source = definition.dynamicTools;
948
- const resolvedTool = source === void 0 || declaredTool !== void 0 ? void 0 : yield* evaluationSafe(source.resolve(toolName));
949
- const tool = declaredTool ?? resolvedTool;
950
- if (tool !== void 0 && tool.kind !== (kind === "query" ? "query" : "mutation"))
951
- return yield* new HostDeclarationInvalid();
1495
+ const toolName = request.operation === "call" ? request.tool : request.name;
1496
+ const location = locate(definition.tools, toolName);
1497
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets);
952
1498
  if (tool === void 0)
953
1499
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
1500
+ const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
1501
+ if (requested !== void 0 && tool.kind !== requested)
1502
+ return yield* new HostKindMismatch({ tool: toolName, requested, actual: tool.kind });
1503
+ const kind = tool.kind === "query" ? "query" : "mutate";
954
1504
  const input = yield* Effect_exports.suspend(
955
1505
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
956
1506
  ).pipe(
957
1507
  Effect_exports.catchCause(
958
- (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(inputInvalid(Cause_exports.squash(cause)))
1508
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(inputInvalid(Cause_exports.squash(cause), request.input))
959
1509
  )
960
1510
  );
961
1511
  if (context.approval !== void 0) {
@@ -1000,24 +1550,22 @@ function dispatch(app, request, context, signal) {
1000
1550
  Match_exports.exhaustive
1001
1551
  );
1002
1552
  }
1003
- const execute = (db) => Effect_exports.gen(function* () {
1004
- transactionOpen = db !== void 0;
1553
+ const replay = context.replay === void 0 ? void 0 : yield* safe2(
1554
+ () => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
1555
+ new HostInputInvalid()
1556
+ );
1557
+ if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
1558
+ const session = yield* sqlSession(replay);
1559
+ const execute = () => Effect_exports.gen(function* () {
1005
1560
  const output = yield* Effect_exports.gen(function* () {
1006
1561
  running = yield* captureTelemetry;
1007
- const fetch = yield* invocationFetch(invocationSignal);
1562
+ const fetch = yield* appInvocationFetch(fetching.signal);
1008
1563
  return yield* tool.run(
1009
1564
  {
1010
1565
  ...bound,
1011
1566
  fetch,
1012
1567
  workflows: kind === "mutate" ? workflowControls : workflowReads,
1013
- ...db === void 0 || native.database === void 0 ? {} : {
1014
- db: authorDatabase(
1015
- native.database.tables,
1016
- db,
1017
- invocationSignal,
1018
- kind === "mutate"
1019
- )
1020
- }
1568
+ sql: kind === "mutate" ? session.writer : session.reader
1021
1569
  },
1022
1570
  input
1023
1571
  );
@@ -1032,14 +1580,15 @@ function dispatch(app, request, context, signal) {
1032
1580
  const error = Cause_exports.squash(cause);
1033
1581
  const provider = parseProviderError(error);
1034
1582
  const response = Schema_exports.decodeUnknownOption(OpenapiResponseError)(error);
1583
+ const mcp = parseMcpError(error, secrets);
1035
1584
  const failure = Schema_exports.decodeUnknownOption(ElicitationFailed)(error);
1036
1585
  return Effect_exports.fail(
1037
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(response) ? new OpenapiResponseError({
1586
+ Option_exports.isSome(provider) ? leavingProviderError(provider.value, secrets, "call") : Option_exports.isSome(response) ? new OpenapiResponseError({
1038
1587
  code: response.value.code,
1039
1588
  status: response.value.status,
1040
1589
  message: response.value.message,
1041
1590
  ...response.value.recovery === void 0 ? {} : { recovery: response.value.recovery }
1042
- }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed()
1591
+ }) : Option_exports.isSome(mcp) ? mcp.value : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1043
1592
  );
1044
1593
  }),
1045
1594
  Effect_exports.withSpan("app.operation.execute", {
@@ -1056,42 +1605,56 @@ function dispatch(app, request, context, signal) {
1056
1605
  new HostOutputInvalid()
1057
1606
  );
1058
1607
  });
1059
- const replay = context.replay === void 0 ? void 0 : yield* safe2(
1060
- () => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
1061
- new HostInputInvalid()
1062
- );
1063
- if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
1064
- if (native.database === void 0) return yield* withinDeadline(execute());
1065
- const storage = context.storage ?? unavailableStorage;
1066
- return yield* storage[kind === "query" ? "read" : "mutate"](
1067
- native.database.schema,
1068
- (db) => withinDeadline(
1069
- replay === void 0 ? execute(db) : db.once(replay.key, replay.fingerprint, () => execute(db))
1070
- )
1071
- ).pipe(
1072
- Effect_exports.catchTags({
1073
- AppDatabaseError: () => Effect_exports.fail(new HostOperationFailed()),
1074
- AppStorageUnavailable: () => Effect_exports.fail(new HostOperationFailed()),
1075
- AppStorageError: () => Effect_exports.fail(new HostOperationFailed())
1076
- })
1077
- );
1608
+ return yield* withinDeadline(execute());
1078
1609
  })
1079
1610
  );
1080
1611
  }
1081
- var parseSkillLoadFailed = (error) => Schema_exports.decodeUnknownOption(SkillLoadFailed)(error).pipe(
1082
- Option_exports.map(
1083
- ({ reason, message, status }) => new SkillLoadFailed({
1084
- reason,
1085
- ...message ? { message } : {},
1086
- ...status === void 0 ? {} : { status }
1087
- })
1088
- )
1089
- );
1090
- var parseMcpError = (error) => Schema_exports.decodeUnknownOption(McpError)(error).pipe(
1091
- Option_exports.map(
1092
- ({ phase, reason, status }) => new McpError({ phase, reason, ...status === void 0 ? {} : { status } })
1093
- )
1094
- );
1612
+ function checkAccount(slots, declared, requirement, context, signal, deadline) {
1613
+ return Effect_exports.gen(function* () {
1614
+ const selection = Object.hasOwn(slots, requirement) ? slots[requirement] : void 0;
1615
+ const slot = Object.hasOwn(declared.accounts, requirement) ? declared.accounts[requirement] : void 0;
1616
+ if (selection === void 0 || slot === void 0) return yield* new HostAccountsInvalid();
1617
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
1618
+ const health = provider.health;
1619
+ if (health === void 0) return yield* new HostOperationNotFound();
1620
+ const { accounts } = yield* bindAccounts(
1621
+ { [requirement]: provider },
1622
+ { accounts: { [requirement]: { ...slot, cardinality: "one" } } },
1623
+ context
1624
+ ).pipe(Effect_exports.withSpan("app.accounts.bind"));
1625
+ const account = accounts[requirement];
1626
+ if (account === void 0 || !("id" in account)) return yield* new HostAccountsInvalid();
1627
+ const result = yield* Effect_exports.suspend(
1628
+ () => Effect_exports.gen(function* () {
1629
+ return yield* health.run({
1630
+ account,
1631
+ fetch: yield* appInvocationFetch(signal),
1632
+ signal,
1633
+ ...deadline === void 0 ? {} : { deadline }
1634
+ });
1635
+ })
1636
+ ).pipe(
1637
+ Effect_exports.catchCause((cause) => {
1638
+ if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
1639
+ const error = Cause_exports.squash(cause);
1640
+ const status = Schema_exports.decodeUnknownOption(ResponseStatusError)(error);
1641
+ const classified = Option_exports.isSome(status) ? Option_exports.fromNullishOr(httpProviderError(status.value.status)) : parseProviderError(error);
1642
+ const secrets = accountSecrets(context.accounts);
1643
+ return Effect_exports.fail(
1644
+ Option_exports.isSome(classified) ? leavingProviderError(accountProviderError(classified.value, account.id), secrets) : new HostOperationFailed(failureDetail(error, secrets))
1645
+ );
1646
+ }),
1647
+ Effect_exports.withSpan("app.account.check")
1648
+ );
1649
+ return yield* safe2(
1650
+ () => Schema_exports.decodeUnknownEffect(AccountCheckResult)(result ?? {}).pipe(
1651
+ Effect_exports.flatMap(Schema_exports.encodeEffect(AccountCheckResult)),
1652
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
1653
+ ),
1654
+ new HostOutputInvalid()
1655
+ );
1656
+ });
1657
+ }
1095
1658
  var errorStatus = Match_exports.type().pipe(
1096
1659
  Match_exports.tagsExhaustive({
1097
1660
  ProviderError: () => 502,
@@ -1103,11 +1666,14 @@ var errorStatus = Match_exports.type().pipe(
1103
1666
  HostAccountsInvalid: () => 422,
1104
1667
  HostInputInvalid: () => 422,
1105
1668
  HostOperationNotFound: () => 404,
1669
+ HostKindMismatch: () => 409,
1106
1670
  HostToolNotFound: () => 404,
1107
1671
  HostToolBlocked: () => 403,
1108
1672
  HostToolApprovalRequired: () => 409,
1109
1673
  HostToolPolicyFailed: () => 500,
1110
1674
  HostOperationFailed: () => 500,
1675
+ DatabaseLimitExceeded: () => 422,
1676
+ DatabaseFieldReserved: () => 422,
1111
1677
  HostDeclarationInvalid: () => 500,
1112
1678
  HostEvaluationFailed: () => 500,
1113
1679
  HostOutputInvalid: () => 500,
@@ -1134,6 +1700,15 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1134
1700
  toolError = true;
1135
1701
  }
1136
1702
  }),
1703
+ // Name what failed on the span; the bounded message stays in the reply only. The host
1704
+ // records an app's own error names and codes as `unrecognized` (telemetry `app-records`).
1705
+ Effect_exports.tapError(
1706
+ (error) => (error._tag === "HostEvaluationFailed" || error._tag === "HostOperationFailed" || error._tag === "HostDeclarationInvalid") && error.errorName !== void 0 ? Effect_exports.annotateCurrentSpan({
1707
+ "error.type": error.errorName,
1708
+ ...error.source === void 0 ? {} : { "executor.failure.source": error.source },
1709
+ ...error.code === void 0 ? {} : { "executor.failure.code": error.code }
1710
+ }) : Effect_exports.void
1711
+ ),
1137
1712
  Effect_exports.withSpan(`app.${command.operation}`)
1138
1713
  );
1139
1714
  if (toolError)
@@ -1152,12 +1727,20 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1152
1727
  )
1153
1728
  ),
1154
1729
  Effect_exports.catchCause(
1155
- (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.logError(cause).pipe(
1156
- Effect_exports.as(
1157
- Response.json(
1158
- { ok: false, error: { _tag: "HostDeclarationInvalid" } },
1159
- { status: 500 }
1160
- )
1730
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : (
1731
+ // The cause can carry any text the app threw; its caller receives that, not the log.
1732
+ Effect_exports.logError("The app's request failed unexpectedly").pipe(
1733
+ Effect_exports.andThen(
1734
+ Schema_exports.encodeEffect(HostError)(
1735
+ declarationInvalid(
1736
+ "The app failed while it was loaded",
1737
+ Cause_exports.squash(cause),
1738
+ accountSecrets(context.accounts)
1739
+ )
1740
+ )
1741
+ ),
1742
+ Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1743
+ Effect_exports.orDie
1161
1744
  )
1162
1745
  )
1163
1746
  )