apps 0.0.1-beta.4 → 0.0.1-beta.40

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-4TLZGG4B.js +729 -0
  5. package/js/chunk-6KABJTDO.js +255 -0
  6. package/js/{chunk-FDNTX5QJ.js → chunk-CQD3WSYH.js} +2 -2
  7. package/js/{chunk-EQB7JMAL.js → chunk-DHX2OI2X.js} +146 -31
  8. package/js/{chunk-EVJUVWN2.js → chunk-DKUEYTYD.js} +463 -218
  9. package/js/chunk-EM4UL26F.js +118 -0
  10. package/js/{chunk-WFSQXYUT.js → chunk-GHXRRFZA.js} +418 -52
  11. package/js/{chunk-5MQZEB6Y.js → chunk-KANDIVIH.js} +40 -12
  12. package/js/chunk-KAQD3DTI.js +16 -0
  13. package/js/chunk-KIM5HXNK.js +49 -0
  14. package/js/{chunk-FW5HBOIK.js → chunk-MXDKXAY4.js} +19117 -18309
  15. package/js/{chunk-2VPJHFOU.js → chunk-MYF7KWUB.js} +128 -24
  16. package/js/{chunk-T2LAZCAD.js → chunk-NKWWPJYX.js} +3 -3
  17. package/js/chunk-OD3KFKZD.js +1617 -0
  18. package/js/{chunk-3M2MEDNL.js → chunk-OTCLXFLL.js} +1337 -188
  19. package/js/chunk-P7MGDPFD.js +240 -0
  20. package/js/chunk-PDS2E2OZ.js +42 -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-6VRYO2BG.js → chunk-SALJXSS3.js} +779 -251
  24. package/js/{chunk-NQ3OMCA5.js → chunk-TT6OU4UG.js} +2 -2
  25. package/js/{chunk-YEJOQEII.js → chunk-UOZMSUJ2.js} +61 -9
  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-XDGUGB2A.js +156 -0
  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 +9 -9
  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 +4 -1
  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 +86 -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-4TLZGG4B.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-XDGUGB2A.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-6KABJTDO.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,48 @@ 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";
74
- import {
75
- OpenapiResponseError
76
- } from "./chunk-SWPD52J7.js";
92
+ SkillFile
93
+ } from "./chunk-UOZMSUJ2.js";
77
94
  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
+ jsonSchemaDecoder,
103
+ jsonSchemaDocument,
104
+ maxAlternativeKeys,
105
+ objectShape,
106
+ unionShape
107
+ } from "./chunk-GHXRRFZA.js";
86
108
  import {
87
109
  JsonObject,
88
110
  JsonValue
89
- } from "./chunk-SATWJKN6.js";
111
+ } from "./chunk-YQ35E7KS.js";
90
112
  import {
113
+ Base64_exports,
91
114
  Cause_exports,
92
115
  Clock_exports,
93
116
  Effect_exports,
94
- Encoding_exports,
95
117
  Match_exports,
96
118
  Option_exports,
97
119
  Redacted_exports,
120
+ SchemaAST_exports,
98
121
  SchemaIssue_exports,
99
122
  Schema_exports,
100
123
  Stream_exports
101
- } from "./chunk-FW5HBOIK.js";
124
+ } from "./chunk-MXDKXAY4.js";
102
125
 
103
126
  // src/implementation/elicitation.ts
104
127
  var prepareElicitation = (input) => Effect_exports.gen(function* () {
@@ -139,19 +162,29 @@ var makeElicit = (handler, signal) => toPromise(
139
162
  var ApprovalDecision = Schema_exports.Literals(["approved", "denied", "user-approval"]);
140
163
 
141
164
  // src/implementation/workflow-context.ts
142
- var workflowSafe = (work) => work.pipe(
165
+ var workflowSafe = (work, secrets) => work.pipe(
143
166
  Effect_exports.catchCause((cause) => {
144
167
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
145
168
  const error = Cause_exports.squash(cause);
146
169
  if (Schema_exports.is(WorkflowFailure)(error)) return Effect_exports.fail(error);
170
+ const { errorName, message } = failureDetail(error, secrets);
147
171
  return Effect_exports.fail(
148
172
  new WorkflowFailure({
149
173
  reason: "execution",
150
- retryable: !(error instanceof NonRetryableError)
174
+ retryable: !(error instanceof NonRetryableError),
175
+ ...errorName === void 0 ? {} : { errorName },
176
+ ...message === void 0 ? {} : { message }
151
177
  })
152
178
  );
153
179
  })
154
180
  );
181
+ var inStep = (step) => (failure) => failure.step === void 0 ? new WorkflowFailure({
182
+ reason: failure.reason,
183
+ retryable: failure.retryable,
184
+ step: step.slice(0, 200),
185
+ ...failure.errorName === void 0 ? {} : { errorName: failure.errorName },
186
+ ...failure.message.length === 0 ? {} : { message: failure.message }
187
+ }) : failure;
155
188
  var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_exports.gen(function* () {
156
189
  const services = yield* Effect_exports.context();
157
190
  const counts = /* @__PURE__ */ new Map();
@@ -206,25 +239,33 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
206
239
  Effect_exports.sync(() => new AbortController()),
207
240
  (controller2) => Effect_exports.sync(() => controller2.abort())
208
241
  );
209
- const ctx = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
242
+ const step2 = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
210
243
  const result = yield* workflowSafe(
211
- Effect_exports.tryPromise({ try: () => callback(ctx), catch: (error) => error })
244
+ Effect_exports.tryPromise({
245
+ try: () => callback(step2.context),
246
+ catch: (error) => error
247
+ }),
248
+ step2.secrets
212
249
  );
213
250
  return yield* Schema_exports.decodeUnknownEffect(WorkflowValue)(result).pipe(
214
251
  Effect_exports.mapError(
215
- () => new WorkflowFailure({ reason: "output", retryable: false })
252
+ () => new WorkflowFailure({
253
+ reason: "output",
254
+ retryable: false,
255
+ message: "The step returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
256
+ })
216
257
  )
217
258
  );
218
259
  })
219
260
  ).pipe(Effect_exports.provideContext(services))
220
261
  )
221
- );
262
+ ).pipe(Effect_exports.mapError(inStep(name)));
222
263
  });
223
264
  const operationStep = (kind, name, operation, input, options) => Effect_exports.gen(function* () {
224
265
  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
266
+ const root = definition.tools?.kind === "router" ? definition.tools : void 0;
267
+ const match = declaredOperations(root).find(
268
+ (entry) => entry.operation === target && entry.operation.kind === kind
228
269
  );
229
270
  if (target === void 0 || match === void 0)
230
271
  return yield* new WorkflowFailure({ reason: "operation", retryable: false });
@@ -243,9 +284,9 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
243
284
  parsed,
244
285
  () => attempt(
245
286
  parsed,
246
- execution.invoke({ kind, name: match[0], input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
287
+ execution.invoke({ kind, name: match.name, input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
247
288
  )
248
- );
289
+ ).pipe(Effect_exports.mapError(inStep(name)));
249
290
  });
250
291
  const invoke = (effect) => toPromise(() => effect.pipe(Effect_exports.provideContext(services)), signal)();
251
292
  const step = {
@@ -284,14 +325,91 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
284
325
  });
285
326
 
286
327
  // src/implementation/input-problems.ts
287
- var leafHook = (issue) => SchemaIssue_exports.hasInput(issue) ? "Invalid value" : SchemaIssue_exports.defaultLeafHook(issue);
328
+ var nativeObjectShape = (ast, limit) => objectShape(
329
+ ast.propertySignatures.flatMap(
330
+ ({ name, type }) => typeof name === "string" ? [{ name, optional: SchemaAST_exports.isOptional(SchemaAST_exports.toEncoded(type)) }] : []
331
+ ),
332
+ ast.indexSignatures.length > 0,
333
+ limit
334
+ );
335
+ var unionMembers = (ast) => SchemaAST_exports.isUnion(ast) ? ast.types.flatMap(unionMembers) : SchemaAST_exports.isUndefined(ast) || SchemaAST_exports.isVoid(ast) ? [] : [ast];
336
+ var fixedValues = (ast) => {
337
+ if (SchemaAST_exports.isLiteral(ast)) return [ast.literal];
338
+ if (SchemaAST_exports.isEnum(ast)) return ast.enums.map(([, value]) => value);
339
+ if (!SchemaAST_exports.isUnion(ast)) return void 0;
340
+ const members = unionMembers(ast).map(fixedValues);
341
+ return members.length > 0 && members.every((values) => values !== void 0) ? members.flat() : void 0;
342
+ };
343
+ var describeMember = (ast) => Match_exports.value(ast).pipe(
344
+ Match_exports.when(
345
+ SchemaAST_exports.isObjects,
346
+ (objects) => objects.propertySignatures.length > 0 ? nativeObjectShape(objects, maxAlternativeKeys) : "object"
347
+ ),
348
+ Match_exports.when(SchemaAST_exports.isArrays, () => "array"),
349
+ Match_exports.when(SchemaAST_exports.isTemplateLiteral, () => "a string matching a template"),
350
+ Match_exports.when(SchemaAST_exports.isString, () => "string"),
351
+ Match_exports.when(SchemaAST_exports.isNumber, () => "number"),
352
+ Match_exports.when(SchemaAST_exports.isBoolean, () => "boolean"),
353
+ Match_exports.when(SchemaAST_exports.isNull, () => "null"),
354
+ Match_exports.orElse(() => "a value with other constraints")
355
+ );
356
+ var memberSelector = (members) => {
357
+ const [first] = members;
358
+ if (members.length < 2 || first === void 0 || !SchemaAST_exports.isObjects(first)) return void 0;
359
+ return first.propertySignatures.map(({ name }) => name).find(
360
+ (name) => typeof name === "string" && members.every(
361
+ (member) => SchemaAST_exports.isObjects(member) && member.propertySignatures.some(
362
+ (property) => property.name === name && fixedValues(SchemaAST_exports.toEncoded(property.type)) !== void 0
363
+ )
364
+ )
365
+ );
366
+ };
367
+ var expectedUnion = (ast) => {
368
+ const members = unionMembers(ast);
369
+ const fixed = members.map(fixedValues);
370
+ const values = fixed.flatMap((memberValues) => memberValues === void 0 ? [] : memberValues);
371
+ const others = members.filter((_, index) => fixed[index] === void 0);
372
+ if (others.length === 0) return `Expected ${allowedValues(values)}`;
373
+ return `Expected ${unionShape(
374
+ [
375
+ ...values.length === 0 ? [] : [allowedValues(values)],
376
+ ...new Set(others.map(describeMember))
377
+ ],
378
+ memberSelector(members)
379
+ )}`;
380
+ };
381
+ var leafHook = (issue) => SchemaIssue_exports.hasInput(issue) ? "Invalid value" : Match_exports.value(issue).pipe(
382
+ Match_exports.tag("InvalidType", ({ ast }) => {
383
+ const values = fixedValues(ast);
384
+ return values !== void 0 ? `Expected ${allowedValues(values)}` : SchemaAST_exports.isObjects(ast) && ast.propertySignatures.length > 0 ? `Expected ${nativeObjectShape(ast)}` : SchemaIssue_exports.defaultLeafHook(issue);
385
+ }),
386
+ Match_exports.orElse(SchemaIssue_exports.defaultLeafHook)
387
+ );
288
388
  var checkHook = (issue) => SchemaIssue_exports.hasInput(issue) || SchemaIssue_exports.hasInput(issue.issue) ? SchemaIssue_exports.defaultCheckHook(issue) ?? "Invalid value" : SchemaIssue_exports.defaultCheckHook(issue);
289
389
  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]";
390
+ var located = (issue, path) => Match_exports.value(issue).pipe(
391
+ Match_exports.tag("Pointer", (pointer) => located(pointer.issue, [...path, ...pointer.path])),
392
+ Match_exports.tag("Composite", ({ issues }) => issues.flatMap((issue2) => located(issue2, path))),
393
+ Match_exports.tag("Encoding", (encoding) => located(encoding.issue, path)),
394
+ Match_exports.tag(
395
+ "AnyOf",
396
+ ({ ast, issues }) => issues.length === 0 ? [{ path, message: expectedUnion(ast) }] : issues.flatMap((issue2) => located(issue2, path))
397
+ ),
398
+ Match_exports.orElse(
399
+ (issue2) => format(issue2).issues.map((problem) => ({
400
+ path: [
401
+ ...path,
402
+ ...(problem.path ?? []).map((key) => typeof key === "object" ? key.key : key)
403
+ ],
404
+ message: problem.message
405
+ }))
406
+ )
407
+ );
408
+ var segment = (key) => typeof key === "number" ? `[${key}]` : typeof key === "string" && echoableKey(key) ? `.${key}` : "[key]";
291
409
  var inputInvalid = (error) => {
292
410
  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));
411
+ const problems = located(error.issue, []).slice(0, maxInputProblems).map(({ path, message }) => {
412
+ const location = path.map(segment);
295
413
  return `${location.length === 0 ? "input" : `input${location.join("")}`}: ${message}`.slice(
296
414
  0,
297
415
  512
@@ -399,7 +517,7 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
399
517
  yield* invoke(hook.unregister, { ...input, state });
400
518
  return null;
401
519
  }
402
- const body = yield* Effect_exports.fromResult(Encoding_exports.decodeBase64(command.request.body)).pipe(
520
+ const body = yield* Effect_exports.fromResult(Base64_exports.decode(command.request.body)).pipe(
403
521
  Effect_exports.mapError(() => new HostInputInvalid())
404
522
  );
405
523
  if (body.byteLength > defaultWebhookTransportLimits.maxBodyBytes)
@@ -448,12 +566,339 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
448
566
  () => Schema_exports.decodeUnknownEffect(WebhookResponseData)({
449
567
  status: response.status,
450
568
  headers,
451
- body: Encoding_exports.encodeBase64(new Uint8Array(bytes))
569
+ body: Base64_exports.encode(new Uint8Array(bytes))
452
570
  }),
453
571
  new HostOutputInvalid()
454
572
  );
455
573
  });
456
574
 
575
+ // src/implementation/sql.ts
576
+ var receipts = `${reservedTablePrefix}step_receipts`;
577
+ var migrationsTable = `${reservedTablePrefix}migrations`;
578
+ var legacyRows = `${reservedTablePrefix}legacy_rows`;
579
+ var materialize = (cursor) => {
580
+ const rows = cursor.toArray();
581
+ return {
582
+ columnNames: cursor.columnNames,
583
+ rowsRead: cursor.rowsRead,
584
+ rowsWritten: cursor.rowsWritten,
585
+ toArray: () => [...rows],
586
+ one: () => {
587
+ if (rows.length !== 1)
588
+ throw new Error(`Expected exactly one row, but the statement returned ${rows.length}.`);
589
+ return rows[0];
590
+ },
591
+ [Symbol.iterator]: () => rows[Symbol.iterator]()
592
+ };
593
+ };
594
+ var isThenable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
595
+ var missingDatabase = () => {
596
+ throw new Error(
597
+ `This app has no database. Add its first migration, such as ${migrationsDirectory}/0001_create_notes.sql with a CREATE TABLE statement, and deploy again.`
598
+ );
599
+ };
600
+ var noDatabase = { exec: missingDatabase, transaction: missingDatabase };
601
+ var settings = [
602
+ "foreign_keys",
603
+ "defer_foreign_keys",
604
+ "ignore_check_constraints",
605
+ "legacy_alter_table",
606
+ "recursive_triggers",
607
+ "reverse_unordered_selects"
608
+ ];
609
+ var readSettings = (storage) => new Map(
610
+ settings.map((name) => [name, Number(storage.sql.exec(`PRAGMA ${name}`).toArray()[0]?.[name])])
611
+ );
612
+ var changedSetting = (storage, baseline) => {
613
+ const current = readSettings(storage);
614
+ return settings.find((name) => current.get(name) !== baseline.get(name));
615
+ };
616
+ var restoreSettings = (storage, baseline) => {
617
+ const current = readSettings(storage);
618
+ for (const [name, value] of baseline)
619
+ if (current.get(name) !== value) storage.sql.exec(`PRAGMA ${name} = ${value}`);
620
+ storage.sql.exec("PRAGMA case_sensitive_like = OFF");
621
+ };
622
+ var ReadRolledBack = class extends Error {
623
+ };
624
+ var authorSql = (storage, options) => {
625
+ let closed = false;
626
+ const live = () => {
627
+ if (closed || options.signal.aborted)
628
+ throw new Error("This call has ended, so its ctx.sql no longer runs statements.");
629
+ };
630
+ let open = false;
631
+ let transactions = 0;
632
+ const baseline = readSettings(storage);
633
+ const checkSettings = () => {
634
+ const changed = changedSetting(storage, baseline);
635
+ if (changed !== void 0)
636
+ throw refuse(
637
+ new Error(
638
+ `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.`
639
+ )
640
+ );
641
+ };
642
+ const changes = () => Number(storage.sql.exec("SELECT total_changes() AS n").toArray()[0]?.n);
643
+ let violation;
644
+ const refuse = (error) => {
645
+ if (open) violation ??= error;
646
+ return error;
647
+ };
648
+ const run = (query, bindings, mode) => {
649
+ try {
650
+ return runStatement(query, bindings, mode);
651
+ } finally {
652
+ restoreSettings(storage, baseline);
653
+ }
654
+ };
655
+ const runStatement = (query, bindings, mode) => {
656
+ live();
657
+ if (mode === "write") {
658
+ const statement = () => {
659
+ const cursor = materialize(storage.sql.exec(query, ...bindings));
660
+ checkSettings();
661
+ return cursor;
662
+ };
663
+ if (!open) return storage.transactionSync(statement);
664
+ try {
665
+ return statement();
666
+ } catch (error) {
667
+ refuse(error instanceof Error ? error : new Error(String(error)));
668
+ throw error;
669
+ }
670
+ }
671
+ if (open) {
672
+ return runStatement(query, bindings, "write");
673
+ }
674
+ const before = changes();
675
+ let read;
676
+ let changed = false;
677
+ try {
678
+ storage.transactionSync(() => {
679
+ read = materialize(storage.sql.exec(query, ...bindings));
680
+ changed = changes() !== before;
681
+ checkSettings();
682
+ throw new ReadRolledBack();
683
+ });
684
+ } catch (error) {
685
+ if (!(error instanceof ReadRolledBack)) throw error;
686
+ }
687
+ if (changed || read === void 0)
688
+ throw new Error(
689
+ 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."
690
+ );
691
+ return read;
692
+ };
693
+ const reader = {
694
+ exec: (query, ...bindings) => run(query, bindings, "read")
695
+ };
696
+ const transactionHandle = () => {
697
+ let active = true;
698
+ const tx = {
699
+ exec: (query, ...bindings) => {
700
+ if (!active)
701
+ throw new Error("This transaction has ended, so its tx no longer runs statements.");
702
+ return run(query, bindings, "write");
703
+ }
704
+ };
705
+ return {
706
+ tx,
707
+ end: () => {
708
+ active = false;
709
+ }
710
+ };
711
+ };
712
+ const transaction = (work) => {
713
+ live();
714
+ if (open) throw new Error("ctx.sql.transaction(...) cannot be nested.");
715
+ const step = options.step;
716
+ if (step !== void 0 && transactions > 0)
717
+ throw new Error(
718
+ "A workflow step mutation opens at most one ctx.sql.transaction(...), which records the step's result."
719
+ );
720
+ transactions += 1;
721
+ violation = void 0;
722
+ const handle = transactionHandle();
723
+ return storage.transactionSync(() => {
724
+ open = true;
725
+ try {
726
+ const complete = () => {
727
+ const value = work(handle.tx);
728
+ if (isThenable(value))
729
+ throw new Error(
730
+ "ctx.sql.transaction(...) callbacks are synchronous and cannot await. Call outside services before or after the transaction."
731
+ );
732
+ if (violation !== void 0) throw violation;
733
+ return value;
734
+ };
735
+ if (step === void 0) return complete();
736
+ storage.sql.exec(
737
+ `CREATE TABLE IF NOT EXISTS ${receipts} (id TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, result TEXT NOT NULL) WITHOUT ROWID`
738
+ );
739
+ const saved = storage.sql.exec(`SELECT fingerprint, result FROM ${receipts} WHERE id = ?`, step.key).toArray()[0];
740
+ if (saved !== void 0) {
741
+ if (saved.fingerprint !== step.fingerprint)
742
+ throw new Error("This workflow step already ran with different input.");
743
+ return JSON.parse(String(saved.result));
744
+ }
745
+ const encoded = JSON.stringify(complete() ?? null);
746
+ storage.sql.exec(
747
+ `INSERT INTO ${receipts} (id, fingerprint, result) VALUES (?, ?, ?)`,
748
+ step.key,
749
+ step.fingerprint,
750
+ encoded
751
+ );
752
+ return JSON.parse(encoded);
753
+ } finally {
754
+ open = false;
755
+ handle.end();
756
+ }
757
+ });
758
+ };
759
+ const writer = {
760
+ // A step's writes go through its one transaction, which also records its receipt.
761
+ exec: (query, ...bindings) => run(query, bindings, options.step ? "read" : "write"),
762
+ transaction
763
+ };
764
+ return {
765
+ reader,
766
+ writer,
767
+ close: () => {
768
+ closed = true;
769
+ }
770
+ };
771
+ };
772
+ var MigrationFileInvalid = class extends Schema_exports.TaggedError()(
773
+ "MigrationFileInvalid",
774
+ { path: Schema_exports.String, reason: Schema_exports.String }
775
+ ) {
776
+ get message() {
777
+ return `${this.path}: ${this.reason}`;
778
+ }
779
+ };
780
+ var MigrationHistoryChanged = class extends Schema_exports.TaggedError()(
781
+ "MigrationHistoryChanged",
782
+ { reason: Schema_exports.String }
783
+ ) {
784
+ get message() {
785
+ 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.`;
786
+ }
787
+ };
788
+ var MigrationFailed = class extends Schema_exports.TaggedError()("MigrationFailed", {
789
+ path: Schema_exports.String,
790
+ reason: Schema_exports.String
791
+ }) {
792
+ get message() {
793
+ return `${this.path} failed: ${this.reason}. No migrations were applied; the previous deployment is still active.`;
794
+ }
795
+ };
796
+ var migrationName = /^(\d+)_[A-Za-z0-9_-]+\.sql$/;
797
+ var sha256 = (text) => Effect_exports.promise(() => crypto.subtle.digest("SHA-256", new TextEncoder().encode(text))).pipe(
798
+ Effect_exports.map(
799
+ (digest) => Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")
800
+ )
801
+ );
802
+ var hasMigrations = (files) => files.some(
803
+ (file) => file.path.startsWith(`${migrationsDirectory}/`) && file.path.endsWith(".sql")
804
+ );
805
+ var migrationsOf = (files) => Effect_exports.gen(function* () {
806
+ const found = [];
807
+ for (const file of files) {
808
+ if (!file.path.startsWith(`${migrationsDirectory}/`) || !file.path.endsWith(".sql")) continue;
809
+ const name = file.path.slice(migrationsDirectory.length + 1);
810
+ const match = migrationName.exec(name);
811
+ if (name.includes("/") || match === null)
812
+ return yield* new MigrationFileInvalid({
813
+ path: file.path,
814
+ reason: "migrations are files directly in migrations/ named like 0001_create_notes.sql: a number that orders them, an underscore, then a name."
815
+ });
816
+ const content = file.content.replaceAll("\r\n", "\n");
817
+ found.push({
818
+ path: file.path,
819
+ order: Number(match[1]),
820
+ content,
821
+ hash: yield* sha256(content)
822
+ });
823
+ }
824
+ const ordered = [...found].sort((left, right) => left.order - right.order);
825
+ for (const [index, migration] of ordered.entries()) {
826
+ const previous = ordered[index - 1];
827
+ if (previous !== void 0 && previous.order === migration.order)
828
+ return yield* new MigrationFileInvalid({
829
+ path: migration.path,
830
+ reason: `it has the same number as ${previous.path}; give each migration its own number.`
831
+ });
832
+ }
833
+ return ordered;
834
+ });
835
+ var History = Schema_exports.Array(
836
+ Schema_exports.Struct({ id: Schema_exports.Number, path: Schema_exports.String, hash: Schema_exports.String })
837
+ );
838
+ var migrate = (storage, files) => Effect_exports.gen(function* () {
839
+ const migrations = yield* migrationsOf(files);
840
+ const baseline = readSettings(storage);
841
+ return yield* Effect_exports.sync(
842
+ () => storage.transactionSync(() => {
843
+ storage.sql.exec(
844
+ `CREATE TABLE IF NOT EXISTS ${migrationsTable} (id INTEGER PRIMARY KEY, path TEXT NOT NULL, hash TEXT NOT NULL, applied_at TEXT NOT NULL)`
845
+ );
846
+ const stored = storage.sql.exec("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'app_rows'").toArray().length > 0;
847
+ storage.sql.exec(`DROP VIEW IF EXISTS ${legacyRows}`);
848
+ storage.sql.exec(
849
+ `CREATE VIEW ${legacyRows} (table_name, id, body) AS ${stored ? "SELECT table_name, id, body FROM app_rows" : "SELECT '', '', '' WHERE 0"}`
850
+ );
851
+ const history = Schema_exports.decodeUnknownSync(History)(
852
+ storage.sql.exec(`SELECT id, path, hash FROM ${migrationsTable} ORDER BY id`).toArray()
853
+ );
854
+ for (const [index, applied] of history.entries()) {
855
+ const current = migrations[index];
856
+ if (current === void 0)
857
+ throw new MigrationHistoryChanged({
858
+ reason: `${applied.path} was applied to this app's database but is no longer in migrations/.`
859
+ });
860
+ if (current.path !== applied.path)
861
+ throw new MigrationHistoryChanged({
862
+ reason: `Migration ${index + 1} was applied as ${applied.path}, but the build has ${current.path} in its place.`
863
+ });
864
+ if (current.hash !== applied.hash)
865
+ throw new MigrationHistoryChanged({
866
+ reason: `${applied.path} changed after it was applied to this app's database.`
867
+ });
868
+ }
869
+ const pending = migrations.slice(history.length);
870
+ const appliedAt = (/* @__PURE__ */ new Date()).toISOString();
871
+ for (const [offset, migration] of pending.entries()) {
872
+ try {
873
+ storage.sql.exec(migration.content);
874
+ } catch (error) {
875
+ throw new MigrationFailed({
876
+ path: migration.path,
877
+ reason: error instanceof Error ? error.message : String(error)
878
+ });
879
+ }
880
+ storage.sql.exec(
881
+ `INSERT INTO ${migrationsTable} (id, path, hash, applied_at) VALUES (?, ?, ?, ?)`,
882
+ history.length + offset + 1,
883
+ migration.path,
884
+ migration.hash,
885
+ appliedAt
886
+ );
887
+ }
888
+ return pending.map((migration, offset) => ({
889
+ id: history.length + offset + 1,
890
+ name: migration.path
891
+ }));
892
+ })
893
+ ).pipe(
894
+ // Both are thrown inside the transaction so that it rolls back; they are expected failures.
895
+ Effect_exports.catchDefect(
896
+ (defect) => Schema_exports.is(MigrationFailed)(defect) || Schema_exports.is(MigrationHistoryChanged)(defect) ? Effect_exports.fail(defect) : Effect_exports.die(defect)
897
+ ),
898
+ Effect_exports.ensuring(Effect_exports.sync(() => restoreSettings(storage, baseline)))
899
+ );
900
+ });
901
+
457
902
  // src/implementation/cache.ts
458
903
  var unavailableCache = {
459
904
  transport: () => Effect_exports.fail(new CacheError({ reason: "unavailable" })),
@@ -469,7 +914,7 @@ var authorCache = (host, accounts, signal, deadline) => {
469
914
  ...options.staleFor === void 0 ? {} : { staleFor: options.staleFor },
470
915
  load: Effect_exports.acquireUseRelease(
471
916
  Effect_exports.sync(() => new AbortController()),
472
- (controller) => invocationFetch(controller.signal).pipe(
917
+ (controller) => appInvocationFetch(controller.signal).pipe(
473
918
  Effect_exports.flatMap(
474
919
  (fetch) => fromPromise(options.load)({
475
920
  fetch,
@@ -523,6 +968,10 @@ var authorCache = (host, accounts, signal, deadline) => {
523
968
  };
524
969
 
525
970
  // src/implementation/host.ts
971
+ var WireCatalog = Schema_exports.Struct({
972
+ tools: Schema_exports.Array(Schema_exports.Union([HostedTool, HostedToolSummary])),
973
+ routers: Schema_exports.Array(HostedRouter)
974
+ });
526
975
  function safe2(work, failure) {
527
976
  return Effect_exports.suspend(work).pipe(
528
977
  Effect_exports.catchCause(
@@ -530,30 +979,39 @@ function safe2(work, failure) {
530
979
  )
531
980
  );
532
981
  }
533
- var evaluationSafe = (work) => work.pipe(
982
+ var evaluationSafe = (work, secrets) => work.pipe(
534
983
  Effect_exports.catchCause((cause) => {
535
984
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
536
985
  const error = Cause_exports.squash(cause);
537
986
  const provider = parseProviderError(error);
538
987
  const skills = parseSkillLoadFailed(error);
539
- const mcp = parseMcpError(error);
988
+ const mcp = parseMcpError(error, secrets);
540
989
  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()
990
+ 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
991
  );
543
992
  })
544
993
  );
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
- });
994
+ var declarationInvalid = (summary, cause, secrets = []) => new HostDeclarationInvalid({
995
+ source: "app",
996
+ errorName: "HostDeclarationInvalid",
997
+ message: boundFailureMessage(
998
+ cause === void 0 ? summary : `${summary}: ${describeFailure(cause)}`,
999
+ secrets
1000
+ )
1001
+ });
1002
+ var declarationSafe = (work, summary) => Effect_exports.suspend(work).pipe(
1003
+ Effect_exports.catchCause(
1004
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(declarationInvalid(summary, Cause_exports.squash(cause)))
1005
+ )
1006
+ );
1007
+ function declaredExposure(exposure) {
1008
+ const named = (kind) => Object.entries(exposure ?? {}).filter(([, value]) => value === kind).map(([field]) => field).sort();
1009
+ const plain = named("plain");
1010
+ const raw = named("raw");
1011
+ return { ...plain.length === 0 ? {} : { plain }, ...raw.length === 0 ? {} : { raw } };
554
1012
  }
555
1013
  function providerDeclaration(provider) {
556
- return safe2(
1014
+ return declarationSafe(
557
1015
  () => Effect_exports.gen(function* () {
558
1016
  const auth = /* @__PURE__ */ new Map();
559
1017
  for (const [name, method] of Object.entries(provider.auth)) {
@@ -562,42 +1020,50 @@ function providerDeclaration(provider) {
562
1020
  auth.set(name, {
563
1021
  type: "secrets",
564
1022
  label: method.label,
565
- fields: yield* jsonSchema(method.fields)
1023
+ fields: yield* jsonSchemaDocument(method.fields),
1024
+ ...declaredExposure(method.exposure)
566
1025
  });
567
1026
  break;
568
1027
  case "oauth2":
569
1028
  auth.set(name, {
570
1029
  type: "oauth2",
571
1030
  ...method.config,
572
- response: yield* jsonSchema(method.response)
1031
+ response: yield* jsonSchemaDocument(method.response),
1032
+ ...declaredExposure(method.exposure)
573
1033
  });
574
1034
  break;
575
1035
  }
576
1036
  }
577
1037
  return yield* Schema_exports.decodeUnknownEffect(DeclaredProvider)({
578
1038
  name: provider.name,
579
- auth: Object.fromEntries(auth)
1039
+ auth: Object.fromEntries(auth),
1040
+ // Order and repetition carry no meaning, so neither changes the provider's identity.
1041
+ ...provider.hosts === void 0 ? {} : { hosts: [...new Set(provider.hosts)].sort() }
580
1042
  });
581
1043
  }),
582
- new HostDeclarationInvalid()
1044
+ `Account provider "${provider.name}" has an invalid declaration`
583
1045
  );
584
1046
  }
585
- function requirements(slots, database) {
1047
+ function requirements(slots, sql) {
586
1048
  return Effect_exports.gen(function* () {
587
1049
  const accounts = /* @__PURE__ */ new Map();
588
1050
  for (const [slot, selection] of Object.entries(slots)) {
1051
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
589
1052
  accounts.set(slot, {
590
1053
  cardinality: selection instanceof ManyAccounts ? "many" : "one",
591
- definition: yield* providerDeclaration(
592
- selection instanceof ManyAccounts ? selection.provider : selection
593
- )
1054
+ definition: yield* providerDeclaration(provider),
1055
+ ...provider.health === void 0 ? {} : { health: true }
594
1056
  });
595
1057
  }
596
1058
  return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
597
1059
  accounts: Object.fromEntries(accounts),
598
1060
  capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
599
- ...database === void 0 ? {} : { database }
600
- }).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1061
+ ...sql ? { sql: true } : {}
1062
+ }).pipe(
1063
+ Effect_exports.mapError(
1064
+ (cause) => declarationInvalid("The app's account declarations are invalid", cause)
1065
+ )
1066
+ );
601
1067
  });
602
1068
  }
603
1069
  function canonical(value) {
@@ -607,6 +1073,9 @@ function canonical(value) {
607
1073
  }
608
1074
  return JSON.stringify(value);
609
1075
  }
1076
+ function withoutHosts({ hosts: _hosts, ...provider }) {
1077
+ return provider;
1078
+ }
610
1079
  function bindAccounts(slots, declarations, context) {
611
1080
  return safe2(
612
1081
  () => Effect_exports.gen(function* () {
@@ -632,7 +1101,7 @@ function bindAccounts(slots, declarations, context) {
632
1101
  for (const account of accounts) {
633
1102
  if (ids.has(account.id)) return yield* Effect_exports.fail(new HostAccountsInvalid());
634
1103
  ids.add(account.id);
635
- if (canonical(account.provider) !== canonical(requirement.definition) || !Object.hasOwn(provider.auth, account.method))
1104
+ if (canonical(withoutHosts(account.provider)) !== canonical(withoutHosts(requirement.definition)) || !Object.hasOwn(provider.auth, account.method))
636
1105
  return yield* Effect_exports.fail(new HostAccountsInvalid());
637
1106
  const method = provider.auth[account.method];
638
1107
  if (method === void 0) return yield* Effect_exports.fail(new HostAccountsInvalid());
@@ -653,22 +1122,95 @@ function bindAccounts(slots, declarations, context) {
653
1122
  new HostAccountsInvalid()
654
1123
  );
655
1124
  }
1125
+ var fetchLifetime = (signal, background) => Effect_exports.acquireRelease(
1126
+ Effect_exports.sync(() => {
1127
+ const controller = new AbortController();
1128
+ let refreshes = 0;
1129
+ let ended = false;
1130
+ const settle = () => {
1131
+ if (ended && refreshes === 0) controller.abort();
1132
+ };
1133
+ const end = () => {
1134
+ ended = true;
1135
+ settle();
1136
+ };
1137
+ signal.addEventListener("abort", end, { once: true });
1138
+ if (signal.aborted) end();
1139
+ const settled = Effect_exports.sync(() => {
1140
+ refreshes -= 1;
1141
+ settle();
1142
+ });
1143
+ return {
1144
+ signal: controller.signal,
1145
+ close: () => {
1146
+ signal.removeEventListener("abort", end);
1147
+ end();
1148
+ },
1149
+ /** Counted from the hand-off, so a refresh that has not started yet keeps the fetch. */
1150
+ background: (task) => Effect_exports.suspend(() => {
1151
+ refreshes += 1;
1152
+ return background(task.pipe(Effect_exports.ensuring(settled))).pipe(
1153
+ Effect_exports.onError(() => settled)
1154
+ );
1155
+ })
1156
+ };
1157
+ }),
1158
+ (lifetime) => Effect_exports.sync(lifetime.close)
1159
+ );
656
1160
  function dispatch(app, request, context, signal) {
657
1161
  return Effect_exports.scoped(
658
1162
  Effect_exports.gen(function* () {
659
- if (!isApp(app)) return yield* Effect_exports.fail(new HostDeclarationInvalid());
1163
+ if (!isApp(app))
1164
+ return yield* Effect_exports.fail(
1165
+ declarationInvalid("The app module's default export is not an app created by defineApp")
1166
+ );
660
1167
  const native = toEffectApp(app);
661
- const declared = yield* requirements(native.accounts, native.database?.schema);
1168
+ const secrets = accountSecrets(context.accounts);
1169
+ const ownsSql = hasMigrations(context.files ?? []);
1170
+ const declared = yield* requirements(native.accounts, ownsSql);
662
1171
  if (request.operation === "requirements")
663
1172
  return yield* safe2(
664
1173
  () => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
665
1174
  new HostDeclarationInvalid()
666
1175
  );
1176
+ if (request.operation === "migrate") {
1177
+ if (!ownsSql) return yield* new HostOperationNotFound();
1178
+ const storage2 = context.storage;
1179
+ if (storage2 === void 0)
1180
+ return yield* new HostOperationFailed(
1181
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1182
+ );
1183
+ const sources = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(SkillFile))(
1184
+ context.files ?? []
1185
+ ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1186
+ const applied = yield* migrate(storage2, sources).pipe(
1187
+ Effect_exports.mapError((error) => new HostOperationFailed(failureDetail(error, secrets))),
1188
+ Effect_exports.withSpan("app.sql.migrate")
1189
+ );
1190
+ return yield* safe2(
1191
+ () => Schema_exports.decodeUnknownEffect(JsonValue)(applied),
1192
+ new HostOutputInvalid()
1193
+ );
1194
+ }
667
1195
  const lifetime = yield* Effect_exports.acquireRelease(
668
1196
  Effect_exports.sync(() => new AbortController()),
669
1197
  (controller) => Effect_exports.sync(() => controller.abort())
670
1198
  );
671
1199
  const invocationSignal = AbortSignal.any([signal, lifetime.signal]);
1200
+ const storage = context.storage;
1201
+ const sqlSession = (step) => !ownsSql ? Effect_exports.succeed({ reader: noDatabase, writer: noDatabase }) : storage === void 0 ? Effect_exports.fail(
1202
+ new HostOperationFailed(
1203
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1204
+ )
1205
+ ) : Effect_exports.acquireRelease(
1206
+ Effect_exports.sync(
1207
+ () => authorSql(storage, {
1208
+ signal: invocationSignal,
1209
+ ...step === void 0 ? {} : { step }
1210
+ })
1211
+ ),
1212
+ (session2) => Effect_exports.sync(session2.close)
1213
+ );
672
1214
  const deadline = context.deadline === void 0 ? void 0 : yield* safe2(
673
1215
  () => Schema_exports.decodeUnknownEffect(InvocationDeadline)(context.deadline),
674
1216
  new HostInputInvalid()
@@ -689,10 +1231,18 @@ function dispatch(app, request, context, signal) {
689
1231
  return yield* new WorkflowFailure({ reason: "engine", retryable: true });
690
1232
  return result;
691
1233
  });
1234
+ if (request.operation === "account-check")
1235
+ return yield* checkAccount(
1236
+ native.accounts,
1237
+ declared,
1238
+ request.requirement,
1239
+ context,
1240
+ invocationSignal,
1241
+ deadline
1242
+ ).pipe(withinDeadline);
692
1243
  let running;
693
- let transactionOpen = false;
694
1244
  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(
1245
+ () => running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
696
1246
  Effect_exports.withSpan("app.tool.elicitation"),
697
1247
  Effect_exports.provideContext(running.context)
698
1248
  ) : Effect_exports.fail(new ElicitationFailed({ reason: "unavailable" }))
@@ -725,6 +1275,7 @@ function dispatch(app, request, context, signal) {
725
1275
  ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
726
1276
  let cacheCommands = 0;
727
1277
  const hostCache = context.cache ?? unavailableCache;
1278
+ const fetching = yield* fetchLifetime(signal, hostCache.background);
728
1279
  const bound = {
729
1280
  cache: authorCache(
730
1281
  {
@@ -732,7 +1283,8 @@ function dispatch(app, request, context, signal) {
732
1283
  transport: (command) => {
733
1284
  cacheCommands += 1;
734
1285
  return hostCache.transport(command);
735
- }
1286
+ },
1287
+ background: fetching.background
736
1288
  },
737
1289
  Redacted_exports.value(context.accounts),
738
1290
  invocationSignal,
@@ -744,37 +1296,43 @@ function dispatch(app, request, context, signal) {
744
1296
  ),
745
1297
  workflows: workflowReads,
746
1298
  signal: invocationSignal,
747
- fetch: yield* invocationFetch(invocationSignal),
1299
+ fetch: yield* appInvocationFetch(fetching.signal),
748
1300
  elicit: makeElicit(delivery, invocationSignal)
749
1301
  };
750
- const definition = yield* evaluationSafe(native.evaluate(bound)).pipe(
1302
+ const definition = yield* evaluationSafe(native.evaluate(bound), secrets).pipe(
751
1303
  Effect_exports.withSpan("app.evaluate")
752
1304
  );
753
1305
  if (request.operation === "skills") {
754
1306
  const declared2 = definition.skills ?? (yield* folderSkillsEffect({ files }).pipe(
755
1307
  Effect_exports.mapError(() => new HostDeclarationInvalid())
756
1308
  ));
757
- const source2 = definition.dynamicSkills;
1309
+ const source = definition.dynamicSkills;
758
1310
  const before = cacheCommands;
759
- const dynamic = source2 === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source2.list)).pipe(
1311
+ const dynamic = source === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source.list), secrets).pipe(
760
1312
  Effect_exports.withSpan("app.skills.load")
761
1313
  );
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;
1314
+ const cached = source !== void 0 && cacheCommands > before;
1315
+ const authored = new Set([...declared2, ...dynamic].map((skill) => skill.name));
1316
+ const routed = (yield* routerSkills(definition.tools).pipe(
1317
+ Effect_exports.withSpan("app.skills.routers")
1318
+ )).filter((skill) => !authored.has(skill.name));
1319
+ const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([
1320
+ ...declared2,
1321
+ ...dynamic,
1322
+ ...routed
1323
+ ]).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1324
+ return request.sources === true ? { skills, dynamic: source !== void 0, cached } : skills;
767
1325
  }
768
1326
  if (request.operation === "workflows") {
769
1327
  return yield* Effect_exports.forEach(
770
1328
  Object.entries(definition.workflows ?? {}),
771
- ([name2, entry]) => safe2(
1329
+ ([name, entry]) => safe2(
772
1330
  () => Effect_exports.gen(function* () {
773
1331
  return yield* Schema_exports.decodeUnknownEffect(HostedWorkflow)({
774
- name: name2,
1332
+ name,
775
1333
  ...entry.description === void 0 ? {} : { description: entry.description },
776
- inputSchema: yield* jsonSchema(entry.input),
777
- ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchema(entry.output) }
1334
+ inputSchema: yield* jsonSchemaDocument(entry.input),
1335
+ ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchemaDocument(entry.output) }
778
1336
  });
779
1337
  }),
780
1338
  new HostDeclarationInvalid()
@@ -807,111 +1365,64 @@ function dispatch(app, request, context, signal) {
807
1365
  new WorkflowFailure({ reason: "credentials", retryable: false })
808
1366
  );
809
1367
  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
1368
+ context: {
1369
+ ...accounts,
1370
+ cache: authorCache(
1371
+ context.cache ?? unavailableCache,
1372
+ Redacted_exports.value(current.accounts),
1373
+ signal2
1374
+ ),
1375
+ files,
1376
+ fetch: yield* appInvocationFetch(signal2),
1377
+ signal: signal2,
1378
+ runId: execution.runId,
1379
+ stepId,
1380
+ idempotencyKey: stepId
1381
+ },
1382
+ // The resolved values, not the app's decoded fields, which may be `Redacted`.
1383
+ secrets: accountSecrets(current.accounts)
822
1384
  };
823
1385
  }),
824
1386
  invocationSignal
825
1387
  );
826
- const output = yield* workflowSafe(entry.run(workflowContext, input2));
1388
+ const output = yield* workflowSafe(entry.run(workflowContext, input2), secrets);
827
1389
  const outputSchema = entry.output;
828
1390
  const decoded = outputSchema === void 0 ? output : yield* safe2(
829
1391
  () => Schema_exports.decodeUnknownEffect(outputSchema)(output),
830
- new WorkflowFailure({ reason: "output", retryable: false })
1392
+ new WorkflowFailure({
1393
+ reason: "output",
1394
+ retryable: false,
1395
+ message: "The workflow's result does not match its declared output schema."
1396
+ })
831
1397
  );
832
1398
  return yield* safe2(
833
1399
  () => Schema_exports.decodeUnknownEffect(WorkflowValue)(decoded),
834
- new WorkflowFailure({ reason: "output", retryable: false })
1400
+ new WorkflowFailure({
1401
+ reason: "output",
1402
+ retryable: false,
1403
+ message: "The workflow returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
1404
+ })
835
1405
  );
836
1406
  }
837
1407
  if (request.operation === "inspect") {
838
1408
  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;
1409
+ const catalog = yield* readCatalog(definition.tools, {
1410
+ summary,
1411
+ secrets,
1412
+ ...request.tools === void 0 ? {} : { wanted: new Set(request.tools) },
1413
+ ...request.scheduled === true ? { scheduled: true } : {},
1414
+ schedules: (name) => Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === name).map(([name2, { tool: _tool, ...schedule }]) => ({ name: name2, ...schedule }))
1415
+ }).pipe(Effect_exports.withSpan("app.catalog.read"));
1416
+ return yield* safe2(
1417
+ () => Schema_exports.encodeEffect(WireCatalog)(catalog).pipe(
1418
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
1419
+ ),
1420
+ new HostDeclarationInvalid()
1421
+ );
912
1422
  }
913
1423
  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(
1424
+ const session2 = yield* sqlSession();
1425
+ return yield* dispatchWebhook(
915
1426
  definition,
916
1427
  request,
917
1428
  {
@@ -921,36 +1432,20 @@ function dispatch(app, request, context, signal) {
921
1432
  workflows: workflowControls,
922
1433
  signal: bound.signal,
923
1434
  fetch: bound.fetch,
924
- ...db === void 0 || native.database === void 0 ? {} : {
925
- db: authorDatabase(native.database.tables, db, invocationSignal, true)
926
- }
1435
+ sql: session2.writer
927
1436
  },
928
1437
  Redacted_exports.value(context.accounts)
929
1438
  );
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
1439
  }
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();
1440
+ const toolName = request.operation === "call" ? request.tool : request.name;
1441
+ const location = locate(definition.tools, toolName);
1442
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets);
952
1443
  if (tool === void 0)
953
1444
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
1445
+ const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
1446
+ if (requested !== void 0 && tool.kind !== requested)
1447
+ return yield* new HostKindMismatch({ tool: toolName, requested, actual: tool.kind });
1448
+ const kind = tool.kind === "query" ? "query" : "mutate";
954
1449
  const input = yield* Effect_exports.suspend(
955
1450
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
956
1451
  ).pipe(
@@ -1000,24 +1495,22 @@ function dispatch(app, request, context, signal) {
1000
1495
  Match_exports.exhaustive
1001
1496
  );
1002
1497
  }
1003
- const execute = (db) => Effect_exports.gen(function* () {
1004
- transactionOpen = db !== void 0;
1498
+ const replay = context.replay === void 0 ? void 0 : yield* safe2(
1499
+ () => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
1500
+ new HostInputInvalid()
1501
+ );
1502
+ if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
1503
+ const session = yield* sqlSession(replay);
1504
+ const execute = () => Effect_exports.gen(function* () {
1005
1505
  const output = yield* Effect_exports.gen(function* () {
1006
1506
  running = yield* captureTelemetry;
1007
- const fetch = yield* invocationFetch(invocationSignal);
1507
+ const fetch = yield* appInvocationFetch(fetching.signal);
1008
1508
  return yield* tool.run(
1009
1509
  {
1010
1510
  ...bound,
1011
1511
  fetch,
1012
1512
  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
- }
1513
+ sql: kind === "mutate" ? session.writer : session.reader
1021
1514
  },
1022
1515
  input
1023
1516
  );
@@ -1032,14 +1525,15 @@ function dispatch(app, request, context, signal) {
1032
1525
  const error = Cause_exports.squash(cause);
1033
1526
  const provider = parseProviderError(error);
1034
1527
  const response = Schema_exports.decodeUnknownOption(OpenapiResponseError)(error);
1528
+ const mcp = parseMcpError(error, secrets);
1035
1529
  const failure = Schema_exports.decodeUnknownOption(ElicitationFailed)(error);
1036
1530
  return Effect_exports.fail(
1037
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(response) ? new OpenapiResponseError({
1531
+ Option_exports.isSome(provider) ? leavingProviderError(provider.value, secrets, "call") : Option_exports.isSome(response) ? new OpenapiResponseError({
1038
1532
  code: response.value.code,
1039
1533
  status: response.value.status,
1040
1534
  message: response.value.message,
1041
1535
  ...response.value.recovery === void 0 ? {} : { recovery: response.value.recovery }
1042
- }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed()
1536
+ }) : Option_exports.isSome(mcp) ? mcp.value : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1043
1537
  );
1044
1538
  }),
1045
1539
  Effect_exports.withSpan("app.operation.execute", {
@@ -1056,42 +1550,56 @@ function dispatch(app, request, context, signal) {
1056
1550
  new HostOutputInvalid()
1057
1551
  );
1058
1552
  });
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
- );
1553
+ return yield* withinDeadline(execute());
1078
1554
  })
1079
1555
  );
1080
1556
  }
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
- );
1557
+ function checkAccount(slots, declared, requirement, context, signal, deadline) {
1558
+ return Effect_exports.gen(function* () {
1559
+ const selection = Object.hasOwn(slots, requirement) ? slots[requirement] : void 0;
1560
+ const slot = Object.hasOwn(declared.accounts, requirement) ? declared.accounts[requirement] : void 0;
1561
+ if (selection === void 0 || slot === void 0) return yield* new HostAccountsInvalid();
1562
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
1563
+ const health = provider.health;
1564
+ if (health === void 0) return yield* new HostOperationNotFound();
1565
+ const { accounts } = yield* bindAccounts(
1566
+ { [requirement]: provider },
1567
+ { accounts: { [requirement]: { ...slot, cardinality: "one" } } },
1568
+ context
1569
+ ).pipe(Effect_exports.withSpan("app.accounts.bind"));
1570
+ const account = accounts[requirement];
1571
+ if (account === void 0 || !("id" in account)) return yield* new HostAccountsInvalid();
1572
+ const result = yield* Effect_exports.suspend(
1573
+ () => Effect_exports.gen(function* () {
1574
+ return yield* health.run({
1575
+ account,
1576
+ fetch: yield* appInvocationFetch(signal),
1577
+ signal,
1578
+ ...deadline === void 0 ? {} : { deadline }
1579
+ });
1580
+ })
1581
+ ).pipe(
1582
+ Effect_exports.catchCause((cause) => {
1583
+ if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
1584
+ const error = Cause_exports.squash(cause);
1585
+ const status = Schema_exports.decodeUnknownOption(ResponseStatusError)(error);
1586
+ const classified = Option_exports.isSome(status) ? Option_exports.fromNullishOr(httpProviderError(status.value.status)) : parseProviderError(error);
1587
+ const secrets = accountSecrets(context.accounts);
1588
+ return Effect_exports.fail(
1589
+ Option_exports.isSome(classified) ? leavingProviderError(accountProviderError(classified.value, account.id), secrets) : new HostOperationFailed(failureDetail(error, secrets))
1590
+ );
1591
+ }),
1592
+ Effect_exports.withSpan("app.account.check")
1593
+ );
1594
+ return yield* safe2(
1595
+ () => Schema_exports.decodeUnknownEffect(AccountCheckResult)(result ?? {}).pipe(
1596
+ Effect_exports.flatMap(Schema_exports.encodeEffect(AccountCheckResult)),
1597
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
1598
+ ),
1599
+ new HostOutputInvalid()
1600
+ );
1601
+ });
1602
+ }
1095
1603
  var errorStatus = Match_exports.type().pipe(
1096
1604
  Match_exports.tagsExhaustive({
1097
1605
  ProviderError: () => 502,
@@ -1103,11 +1611,14 @@ var errorStatus = Match_exports.type().pipe(
1103
1611
  HostAccountsInvalid: () => 422,
1104
1612
  HostInputInvalid: () => 422,
1105
1613
  HostOperationNotFound: () => 404,
1614
+ HostKindMismatch: () => 409,
1106
1615
  HostToolNotFound: () => 404,
1107
1616
  HostToolBlocked: () => 403,
1108
1617
  HostToolApprovalRequired: () => 409,
1109
1618
  HostToolPolicyFailed: () => 500,
1110
1619
  HostOperationFailed: () => 500,
1620
+ DatabaseLimitExceeded: () => 422,
1621
+ DatabaseFieldReserved: () => 422,
1111
1622
  HostDeclarationInvalid: () => 500,
1112
1623
  HostEvaluationFailed: () => 500,
1113
1624
  HostOutputInvalid: () => 500,
@@ -1134,6 +1645,15 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1134
1645
  toolError = true;
1135
1646
  }
1136
1647
  }),
1648
+ // Name what failed on the span; the bounded message stays in the reply only. The host
1649
+ // records an app's own error names and codes as `unrecognized` (telemetry `app-records`).
1650
+ Effect_exports.tapError(
1651
+ (error) => (error._tag === "HostEvaluationFailed" || error._tag === "HostOperationFailed" || error._tag === "HostDeclarationInvalid") && error.errorName !== void 0 ? Effect_exports.annotateCurrentSpan({
1652
+ "error.type": error.errorName,
1653
+ ...error.source === void 0 ? {} : { "executor.failure.source": error.source },
1654
+ ...error.code === void 0 ? {} : { "executor.failure.code": error.code }
1655
+ }) : Effect_exports.void
1656
+ ),
1137
1657
  Effect_exports.withSpan(`app.${command.operation}`)
1138
1658
  );
1139
1659
  if (toolError)
@@ -1152,12 +1672,20 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1152
1672
  )
1153
1673
  ),
1154
1674
  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
- )
1675
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : (
1676
+ // The cause can carry any text the app threw; its caller receives that, not the log.
1677
+ Effect_exports.logError("The app's request failed unexpectedly").pipe(
1678
+ Effect_exports.andThen(
1679
+ Schema_exports.encodeEffect(HostError)(
1680
+ declarationInvalid(
1681
+ "The app failed while it was loaded",
1682
+ Cause_exports.squash(cause),
1683
+ accountSecrets(context.accounts)
1684
+ )
1685
+ )
1686
+ ),
1687
+ Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1688
+ Effect_exports.orDie
1161
1689
  )
1162
1690
  )
1163
1691
  )