apps 0.0.1-beta.7 → 0.0.1-beta.70

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 (178) hide show
  1. package/README.md +25 -22
  2. package/framework-reference.json +1 -1
  3. package/js/{chunk-UESPOTUI.js → chunk-2YSTJMBD.js} +899 -190
  4. package/js/{chunk-RJDDBDSN.js → chunk-3CVQ3VPP.js} +762 -171
  5. package/js/chunk-3R3KFCDU.js +426 -0
  6. package/js/{chunk-FL2QR3XW.js → chunk-4NCIPADO.js} +326 -69
  7. package/js/chunk-5FHWNLCI.js +88 -0
  8. package/js/{chunk-M3B3DE4K.js → chunk-74YVXBKY.js} +463 -218
  9. package/js/chunk-7LMU3ER3.js +274 -0
  10. package/js/chunk-CDXQDN7W.js +92 -0
  11. package/js/{chunk-RFVIONFX.js → chunk-ECCWT5GJ.js} +79 -41
  12. package/js/{chunk-UK573G7W.js → chunk-EOPQ727L.js} +87 -51
  13. package/js/{chunk-27F7W2LG.js → chunk-H2CJWXA3.js} +2 -2
  14. package/js/{chunk-JU7VHODU.js → chunk-H72MEDMN.js} +65 -10
  15. package/js/{chunk-CDL5PM2Q.js → chunk-IFJU5SYQ.js} +19082 -18402
  16. package/js/{chunk-VFZKSM3T.js → chunk-JPEUKEV4.js} +3 -3
  17. package/js/{chunk-WLE7WX2U.js → chunk-JW5LYSER.js} +2262 -474
  18. package/js/{chunk-5T57N25Q.js → chunk-KGCTYL2S.js} +511 -63
  19. package/js/{chunk-KUMBKVJD.js → chunk-KLYSEHUD.js} +2 -2
  20. package/js/chunk-M5OLYYNU.js +347 -0
  21. package/js/chunk-MHB7IFG7.js +49 -0
  22. package/js/chunk-OD3KFKZD.js +1617 -0
  23. package/js/{chunk-57RKNWL2.js → chunk-PD6I2SDG.js} +4 -4
  24. package/js/{chunk-NKLWZJLE.js → chunk-RUP4JMKO.js} +25 -14
  25. package/js/{chunk-IJX4CYZO.js → chunk-TUMGL2OC.js} +228 -264
  26. package/js/{chunk-72JNVHPK.js → chunk-WDIVWSDG.js} +4 -3
  27. package/js/{chunk-CMYUWAX7.js → chunk-WGQP62EG.js} +126 -31
  28. package/js/{chunk-IPI4MFSN.js → chunk-XBG7HHXC.js} +2 -2
  29. package/js/{chunk-Z5M2LQOZ.js → chunk-ZEJ3IKEC.js} +67 -55
  30. package/js/chunk-ZR7QAG67.js +171 -0
  31. package/js/client.js +142 -94
  32. package/js/contracts.js +125 -26
  33. package/js/effect.js +19 -19
  34. package/js/{es-APDZKREY.js → es-DIULA3ZF.js} +62 -1659
  35. package/js/graphql.js +50 -40
  36. package/js/host.js +83 -58
  37. package/js/index.js +131 -46
  38. package/js/mcp/effect.js +23 -21
  39. package/js/mcp/stdio.js +44 -34
  40. package/js/mcp.js +76 -53
  41. package/js/openapi.js +4063 -1359
  42. package/js/react.js +2 -3
  43. package/js/skills/effect.js +6 -3
  44. package/js/skills.js +208 -81
  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 +3 -4
  51. package/runtime.json +1 -1
  52. package/types/app-cache/src/contracts/cache.d.ts +2 -0
  53. package/types/app-cache/src/index.d.ts +10 -1
  54. package/types/apps/src/contracts/api-response-error.d.ts +4 -0
  55. package/types/apps/src/contracts/app.d.ts +7 -3
  56. package/types/apps/src/contracts/cache.d.ts +20 -0
  57. package/types/apps/src/contracts/context.d.ts +19 -11
  58. package/types/apps/src/contracts/elicitation.d.ts +6 -6
  59. package/types/apps/src/contracts/events.d.ts +93 -0
  60. package/types/apps/src/contracts/failure.d.ts +30 -1
  61. package/types/apps/src/contracts/graphql.d.ts +2 -1
  62. package/types/apps/src/contracts/host.d.ts +641 -16
  63. package/types/apps/src/contracts/live.d.ts +2 -0
  64. package/types/apps/src/contracts/mcp.d.ts +80 -10
  65. package/types/apps/src/contracts/network.d.ts +120 -0
  66. package/types/apps/src/contracts/openapi-compile.d.ts +82 -3
  67. package/types/apps/src/contracts/openapi.d.ts +41 -9
  68. package/types/apps/src/contracts/operations.d.ts +8 -4
  69. package/types/apps/src/contracts/placement.d.ts +102 -0
  70. package/types/apps/src/contracts/protocol-version.d.ts +2 -2
  71. package/types/apps/src/contracts/protocols/1.d.ts +733 -81
  72. package/types/apps/src/contracts/protocols/10.d.ts +1450 -0
  73. package/types/apps/src/contracts/protocols/2.d.ts +69 -26
  74. package/types/apps/src/contracts/protocols/3.d.ts +133 -33
  75. package/types/apps/src/contracts/protocols/4.d.ts +122 -45
  76. package/types/apps/src/contracts/protocols/5.d.ts +157 -47
  77. package/types/apps/src/contracts/protocols/6.d.ts +1629 -0
  78. package/types/apps/src/contracts/protocols/7.d.ts +1785 -0
  79. package/types/apps/src/contracts/protocols/8.d.ts +1182 -0
  80. package/types/apps/src/contracts/protocols/9.d.ts +1104 -0
  81. package/types/apps/src/contracts/protocols/current.d.ts +3842 -0
  82. package/types/apps/src/contracts/protocols/oauth-6.d.ts +74 -0
  83. package/types/apps/src/contracts/protocols/oauth.d.ts +134 -0
  84. package/types/apps/src/contracts/provider-error.d.ts +9 -0
  85. package/types/apps/src/contracts/provider.d.ts +90 -6
  86. package/types/apps/src/contracts/skills.d.ts +50 -13
  87. package/types/apps/src/contracts/sql.d.ts +63 -0
  88. package/types/apps/src/contracts/ui.d.ts +19 -1
  89. package/types/apps/src/contracts/workflows.d.ts +6 -0
  90. package/types/apps/src/facet.d.ts +4 -5
  91. package/types/apps/src/host.d.ts +5 -0
  92. package/types/apps/src/implementation/account-router.d.ts +4 -3
  93. package/types/apps/src/implementation/authoring.d.ts +25 -5
  94. package/types/apps/src/implementation/browser-scripts.gen.d.ts +6 -0
  95. package/types/apps/src/implementation/cache.d.ts +4 -0
  96. package/types/apps/src/implementation/catalog-cache.d.ts +35 -4
  97. package/types/apps/src/implementation/elicitation.d.ts +18 -15
  98. package/types/apps/src/implementation/events.d.ts +59 -0
  99. package/types/apps/src/implementation/failure-detail.d.ts +25 -3
  100. package/types/apps/src/implementation/graphql-catalog.d.ts +3 -3
  101. package/types/apps/src/implementation/graphql.d.ts +4 -3
  102. package/types/apps/src/implementation/input-problems.d.ts +6 -2
  103. package/types/apps/src/implementation/invocation-timing.d.ts +16 -0
  104. package/types/apps/src/implementation/live.d.ts +2 -2
  105. package/types/apps/src/implementation/mcp-call.d.ts +6 -5
  106. package/types/apps/src/implementation/mcp-catalog.d.ts +6 -4
  107. package/types/apps/src/implementation/mcp-client.d.ts +17 -9
  108. package/types/apps/src/implementation/mcp-stdio.d.ts +1 -1
  109. package/types/apps/src/implementation/mcp-tools.d.ts +2 -1
  110. package/types/apps/src/implementation/mcp.d.ts +20 -9
  111. package/types/apps/src/implementation/network.d.ts +16 -0
  112. package/types/apps/src/implementation/openapi-compile.d.ts +26 -6
  113. package/types/apps/src/implementation/openapi-document.d.ts +46 -19
  114. package/types/apps/src/implementation/openapi-names.d.ts +9 -4
  115. package/types/apps/src/implementation/openapi-request.d.ts +10 -2
  116. package/types/apps/src/implementation/openapi-source.d.ts +18 -0
  117. package/types/apps/src/implementation/openapi-upgrade.d.ts +4 -0
  118. package/types/apps/src/implementation/operations.d.ts +17 -2
  119. package/types/apps/src/implementation/optimistic.d.ts +1 -1
  120. package/types/apps/src/implementation/placement.d.ts +60 -0
  121. package/types/apps/src/implementation/protocol-operations.d.ts +3 -0
  122. package/types/apps/src/implementation/provider-error.d.ts +28 -1
  123. package/types/apps/src/implementation/provider.d.ts +18 -3
  124. package/types/apps/src/implementation/query-commit.d.ts +1 -1
  125. package/types/apps/src/implementation/router-catalog.d.ts +11 -13
  126. package/types/apps/src/implementation/router.d.ts +16 -5
  127. package/types/apps/src/implementation/runtime-yield.d.ts +7 -0
  128. package/types/apps/src/implementation/schema.d.ts +90 -10
  129. package/types/apps/src/implementation/skills.d.ts +18 -24
  130. package/types/apps/src/implementation/sql.d.ts +71 -0
  131. package/types/apps/src/implementation/ui-account-notice.d.ts +9 -0
  132. package/types/apps/src/implementation/ui-auth.d.ts +1 -1
  133. package/types/apps/src/implementation/ui-client.d.ts +2 -2
  134. package/types/apps/src/implementation/ui-document.d.ts +5 -0
  135. package/types/apps/src/implementation/ui-errors.d.ts +1 -1
  136. package/types/apps/src/implementation/ui-serving.d.ts +11 -5
  137. package/types/apps/src/implementation/ui-watch.d.ts +1 -1
  138. package/types/apps/src/implementation/upstream-error.d.ts +7 -0
  139. package/types/apps/src/implementation/webhooks.d.ts +1 -1
  140. package/types/apps/src/implementation/workflows.d.ts +1 -1
  141. package/types/apps/src/index.d.ts +55 -13
  142. package/types/apps/src/mcp.d.ts +20 -1
  143. package/types/apps/src/openapi.d.ts +1 -1
  144. package/types/apps/src/react.d.ts +1 -1
  145. package/types/apps/src/skills.d.ts +10 -8
  146. package/types/telemetry/src/app-records.d.ts +42 -0
  147. package/types/telemetry/src/browser-operations.d.ts +7 -4
  148. package/types/telemetry/src/browser.d.ts +8 -3
  149. package/types/telemetry/src/config.d.ts +2 -2
  150. package/types/telemetry/src/index.d.ts +2 -1
  151. package/types/telemetry/src/layer.d.ts +2 -2
  152. package/types/telemetry/src/measurements.d.ts +1 -1
  153. package/types/telemetry/src/ownership.d.ts +56 -0
  154. package/types/telemetry/src/recorded-failure.d.ts +29 -0
  155. package/types/telemetry/src/relay.d.ts +16 -6
  156. package/types/telemetry/src/span-attributes.d.ts +17 -1
  157. package/types/telemetry/src/transport.d.ts +8 -1
  158. package/types/utils/src/api-error.d.ts +55 -0
  159. package/types/utils/src/connection-failure.d.ts +33 -0
  160. package/types/utils/src/recorded-message.d.ts +18 -0
  161. package/types/utils/src/user-facing-error.d.ts +83 -0
  162. package/js/chunk-MKWZPDR6.js +0 -63
  163. package/js/chunk-N7YDVXYJ.js +0 -186
  164. package/js/chunk-OCYUEU47.js +0 -224
  165. package/js/chunk-PJJ24GU7.js +0 -877
  166. package/js/chunk-PZB6T6KU.js +0 -19
  167. package/js/chunk-R3EV5FTO.js +0 -97
  168. package/js/chunk-YXQHV65J.js +0 -242
  169. package/js/chunk-ZQINWV4W.js +0 -630
  170. package/types/app-data/src/implementation/cursor.d.ts +0 -10
  171. package/types/app-data/src/implementation/index-key.d.ts +0 -7
  172. package/types/app-data/src/implementation/promise.d.ts +0 -68
  173. package/types/app-data/src/implementation/range.d.ts +0 -8
  174. package/types/app-data/src/implementation/schema.d.ts +0 -18
  175. package/types/app-data/src/implementation/sqlite.d.ts +0 -11
  176. package/types/app-data/src/index.d.ts +0 -4
  177. package/types/apps/src/contracts/storage.d.ts +0 -68
  178. package/types/apps/src/implementation/storage.d.ts +0 -15
@@ -1,39 +1,45 @@
1
1
  import {
2
2
  makeCache
3
- } from "./chunk-NKLWZJLE.js";
3
+ } from "./chunk-RUP4JMKO.js";
4
4
  import {
5
5
  accountSecrets,
6
6
  boundFailureMessage,
7
7
  describeFailure,
8
8
  failureDetail,
9
+ leavingProviderError,
10
+ parseMcpError,
11
+ parseSkillLoadFailed,
9
12
  readCatalog,
10
13
  routerSkills
11
- } from "./chunk-FL2QR3XW.js";
14
+ } from "./chunk-4NCIPADO.js";
15
+ import {
16
+ appInvocationFetch
17
+ } from "./chunk-MHB7IFG7.js";
12
18
  import {
13
19
  folderSkillsEffect
14
- } from "./chunk-IPI4MFSN.js";
20
+ } from "./chunk-XBG7HHXC.js";
15
21
  import {
16
22
  ResponseStatusError,
17
- authorDatabase,
23
+ declaredEvents,
18
24
  isApp,
25
+ makeEmitter,
19
26
  toEffectApp,
20
- unavailableStorage
21
- } from "./chunk-YXQHV65J.js";
22
- import {
23
- parseDatabaseSchema
24
- } from "./chunk-ZQINWV4W.js";
27
+ withPlacements
28
+ } from "./chunk-3R3KFCDU.js";
25
29
  import {
26
30
  declaredOperations,
27
- fromPromise,
28
31
  locate,
29
- nativeOperation,
30
- toPromise
31
- } from "./chunk-Z5M2LQOZ.js";
32
+ nativeOperation
33
+ } from "./chunk-ZEJ3IKEC.js";
32
34
  import {
33
35
  accountProviderError,
36
+ appCode,
37
+ fromPromise,
34
38
  httpProviderError,
35
- parseProviderError
36
- } from "./chunk-MKWZPDR6.js";
39
+ method,
40
+ parseProviderError,
41
+ toPromise
42
+ } from "./chunk-ZR7QAG67.js";
37
43
  import {
38
44
  AccountCheckResult,
39
45
  DeclaredProvider,
@@ -62,9 +68,9 @@ import {
62
68
  HostedWebhook,
63
69
  HostedWorkflow,
64
70
  InvocationDeadline,
71
+ InvocationTimingSink,
65
72
  ManualWebhookSetup,
66
73
  ManyAccounts,
67
- McpError,
68
74
  NonRetryableError,
69
75
  OpenapiResponseError,
70
76
  ResolvedAccounts,
@@ -80,42 +86,84 @@ import {
80
86
  approvalElicitation,
81
87
  defaultWebhookTransportLimits,
82
88
  maxInputProblems,
89
+ migrationsDirectory,
90
+ normalizePlacements,
91
+ reservedTablePrefix,
92
+ sqlBindingsLimit,
83
93
  workflowDurationMillis
84
- } from "./chunk-WLE7WX2U.js";
94
+ } from "./chunk-JW5LYSER.js";
85
95
  import {
86
96
  CacheError
87
- } from "./chunk-R3EV5FTO.js";
97
+ } from "./chunk-7LMU3ER3.js";
88
98
  import {
89
99
  AppSkills,
90
- SkillFile,
91
- SkillLoadFailed
92
- } from "./chunk-JU7VHODU.js";
93
- import {
94
- captureTelemetry,
95
- invocationFetch
96
- } from "./chunk-RJDDBDSN.js";
100
+ SkillFile
101
+ } from "./chunk-H72MEDMN.js";
97
102
  import {
103
+ allowedValues,
98
104
  decoderOf,
105
+ echoableKey,
99
106
  importedJsonSchema,
107
+ importedSchemaKeys,
100
108
  jsonSchemaDecoder,
101
- jsonSchemaDocument
102
- } from "./chunk-5T57N25Q.js";
109
+ jsonSchemaDocument,
110
+ maxAlternativeKeys,
111
+ missingKey,
112
+ missingKeyText,
113
+ objectShape,
114
+ unionShape
115
+ } from "./chunk-KGCTYL2S.js";
116
+ import {
117
+ captureTelemetry,
118
+ makeOwnershipAccounting,
119
+ measuredSpan,
120
+ owned
121
+ } from "./chunk-3CVQ3VPP.js";
103
122
  import {
104
123
  JsonObject,
105
124
  JsonValue
106
- } from "./chunk-27F7W2LG.js";
125
+ } from "./chunk-H2CJWXA3.js";
107
126
  import {
127
+ Base64_exports,
108
128
  Cause_exports,
109
129
  Clock_exports,
110
130
  Effect_exports,
111
- Encoding_exports,
112
131
  Match_exports,
113
132
  Option_exports,
114
133
  Redacted_exports,
134
+ SchemaAST_exports,
115
135
  SchemaIssue_exports,
116
136
  Schema_exports,
117
137
  Stream_exports
118
- } from "./chunk-CDL5PM2Q.js";
138
+ } from "./chunk-IFJU5SYQ.js";
139
+
140
+ // src/implementation/invocation-timing.ts
141
+ var elicitationWaitSpan = "app.elicitation.wait";
142
+ var workflowControlSpan = "app.workflow.control";
143
+ var timedInvocation = (operation) => (effect) => Effect_exports.gen(function* () {
144
+ const report = yield* InvocationTimingSink;
145
+ return yield* effect.pipe(
146
+ measuredSpan(`app.${operation}`, {}, (start) => {
147
+ const accounting = makeOwnershipAccounting(start, "executor");
148
+ return {
149
+ around: accounting.observe,
150
+ end: (end, span) => {
151
+ const spent = accounting.read(end);
152
+ report({
153
+ elapsedMs: Number(end - start) / 1e6,
154
+ upstreamMs: spent.upstream,
155
+ elicitationMs: spent.person,
156
+ authoredMs: spent.app
157
+ });
158
+ span.attribute("executor.upstream.wait_ms", spent.upstream);
159
+ span.attribute("executor.elicitation.wait_ms", spent.person);
160
+ span.attribute("executor.authored_ms", spent.app);
161
+ span.attribute("executor.overhead_ms", spent.executor);
162
+ }
163
+ };
164
+ })
165
+ );
166
+ });
119
167
 
120
168
  // src/implementation/elicitation.ts
121
169
  var prepareElicitation = (input) => Effect_exports.gen(function* () {
@@ -143,13 +191,17 @@ var prepareElicitation = (input) => Effect_exports.gen(function* () {
143
191
  });
144
192
  return { request, respond };
145
193
  });
146
- var makeElicit = (handler, signal) => toPromise(
194
+ var makeElicit = (handler, signal, telemetry) => toPromise(
147
195
  (input) => Effect_exports.gen(function* () {
148
196
  if (handler === void 0) return yield* new ElicitationFailed({ reason: "unavailable" });
149
197
  const form = yield* prepareElicitation(input);
150
- return yield* handler(form.request, signal).pipe(Effect_exports.flatMap(form.respond));
198
+ return yield* handler(form.request, signal).pipe(
199
+ owned("person", elicitationWaitSpan),
200
+ Effect_exports.flatMap(form.respond)
201
+ );
151
202
  }),
152
- signal
203
+ signal,
204
+ telemetry
153
205
  );
154
206
 
155
207
  // src/contracts/approval.ts
@@ -235,10 +287,7 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
235
287
  );
236
288
  const step2 = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
237
289
  const result = yield* workflowSafe(
238
- Effect_exports.tryPromise({
239
- try: () => callback(step2.context),
240
- catch: (error) => error
241
- }),
290
+ fromPromise(callback, "step")(step2.context),
242
291
  step2.secrets
243
292
  );
244
293
  return yield* Schema_exports.decodeUnknownEffect(WorkflowValue)(result).pipe(
@@ -319,15 +368,144 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
319
368
  });
320
369
 
321
370
  // src/implementation/input-problems.ts
322
- var leafHook = (issue) => SchemaIssue_exports.hasInput(issue) ? "Invalid value" : SchemaIssue_exports.defaultLeafHook(issue);
371
+ var nativeObjectShape = (ast, limit) => objectShape(
372
+ ast.propertySignatures.flatMap(
373
+ ({ name, type }) => typeof name === "string" ? [{ name, optional: SchemaAST_exports.isOptional(SchemaAST_exports.toEncoded(type)) }] : []
374
+ ),
375
+ ast.indexSignatures.length > 0,
376
+ limit
377
+ );
378
+ var unionMembers = (ast) => SchemaAST_exports.isUnion(ast) ? ast.types.flatMap(unionMembers) : SchemaAST_exports.isUndefined(ast) || SchemaAST_exports.isVoid(ast) ? [] : [ast];
379
+ var fixedValues = (ast) => {
380
+ if (SchemaAST_exports.isLiteral(ast)) return [ast.literal];
381
+ if (SchemaAST_exports.isEnum(ast)) return ast.enums.map(([, value]) => value);
382
+ if (!SchemaAST_exports.isUnion(ast)) return void 0;
383
+ const members = unionMembers(ast).map(fixedValues);
384
+ return members.length > 0 && members.every((values) => values !== void 0) ? members.flat() : void 0;
385
+ };
386
+ var describeMember = (ast) => Match_exports.value(ast).pipe(
387
+ Match_exports.when(
388
+ SchemaAST_exports.isObjects,
389
+ (objects) => objects.propertySignatures.length > 0 ? nativeObjectShape(objects, maxAlternativeKeys) : "object"
390
+ ),
391
+ Match_exports.when(SchemaAST_exports.isArrays, () => "array"),
392
+ Match_exports.when(SchemaAST_exports.isTemplateLiteral, () => "a string matching a template"),
393
+ Match_exports.when(SchemaAST_exports.isString, () => "string"),
394
+ Match_exports.when(SchemaAST_exports.isNumber, () => "number"),
395
+ Match_exports.when(SchemaAST_exports.isBoolean, () => "boolean"),
396
+ Match_exports.when(SchemaAST_exports.isNull, () => "null"),
397
+ Match_exports.orElse(() => "a value with other constraints")
398
+ );
399
+ var memberSelector = (members) => {
400
+ const [first] = members;
401
+ if (members.length < 2 || first === void 0 || !SchemaAST_exports.isObjects(first)) return void 0;
402
+ return first.propertySignatures.map(({ name }) => name).find(
403
+ (name) => typeof name === "string" && members.every(
404
+ (member) => SchemaAST_exports.isObjects(member) && member.propertySignatures.some(
405
+ (property) => property.name === name && fixedValues(SchemaAST_exports.toEncoded(property.type)) !== void 0
406
+ )
407
+ )
408
+ );
409
+ };
410
+ var unionExpectation = (ast) => {
411
+ const members = unionMembers(ast);
412
+ const fixed = members.map(fixedValues);
413
+ const values = fixed.flatMap((memberValues) => memberValues === void 0 ? [] : memberValues);
414
+ const others = members.filter((_, index) => fixed[index] === void 0);
415
+ if (others.length === 0) return allowedValues(values);
416
+ return unionShape(
417
+ [
418
+ ...values.length === 0 ? [] : [allowedValues(values)],
419
+ ...new Set(others.map(describeMember))
420
+ ],
421
+ memberSelector(members)
422
+ );
423
+ };
424
+ var expectedUnion = (ast) => `Expected ${unionExpectation(ast)}`;
425
+ var expectedValue = (ast) => {
426
+ const encoded = SchemaAST_exports.toEncoded(ast);
427
+ const values = fixedValues(encoded);
428
+ if (values !== void 0) return allowedValues(values);
429
+ const members = unionMembers(encoded);
430
+ const [only] = members;
431
+ if (only === void 0) return void 0;
432
+ if (members.length > 1 && SchemaAST_exports.isUnion(encoded)) return unionExpectation(encoded);
433
+ if (SchemaAST_exports.isObjects(only) && only.propertySignatures.length > 0)
434
+ return nativeObjectShape(only);
435
+ const described = describeMember(only);
436
+ return described === "a value with other constraints" ? void 0 : described;
437
+ };
438
+ var leafHook = (issue) => SchemaIssue_exports.hasInput(issue) ? "Invalid value" : Match_exports.value(issue).pipe(
439
+ Match_exports.tag("InvalidType", ({ ast }) => {
440
+ const values = fixedValues(ast);
441
+ return values !== void 0 ? `Expected ${allowedValues(values)}` : SchemaAST_exports.isObjects(ast) && ast.propertySignatures.length > 0 ? `Expected ${nativeObjectShape(ast)}` : SchemaIssue_exports.defaultLeafHook(issue);
442
+ }),
443
+ Match_exports.orElse(SchemaIssue_exports.defaultLeafHook)
444
+ );
323
445
  var checkHook = (issue) => SchemaIssue_exports.hasInput(issue) || SchemaIssue_exports.hasInput(issue.issue) ? SchemaIssue_exports.defaultCheckHook(issue) ?? "Invalid value" : SchemaIssue_exports.defaultCheckHook(issue);
324
446
  var format = SchemaIssue_exports.makeFormatterStandardSchemaV1({ leafHook, checkHook });
325
- var segment = (key) => typeof key === "number" ? `[${key}]` : typeof key === "string" && /^[A-Za-z_$][\w$-]{0,63}$/.test(key) ? `.${key}` : "[key]";
326
- var inputInvalid = (error) => {
447
+ var declaredKey = (parent, key) => parent !== void 0 && SchemaAST_exports.isObjects(parent) ? parent.propertySignatures.find(({ name }) => name === key)?.type : void 0;
448
+ var nativeKeys = (parent) => (key) => parent.indexSignatures.length > 0 || parent.propertySignatures.some(({ name }) => name === key);
449
+ var located = (issue, path, parent) => Match_exports.value(issue).pipe(
450
+ Match_exports.tag("Pointer", (pointer) => {
451
+ const declared = pointer.issue._tag === "MissingKey" && pointer.path.length === 1 ? declaredKey(parent, pointer.path[0]) : void 0;
452
+ return declared === void 0 || parent === void 0 || !SchemaAST_exports.isObjects(parent) ? located(pointer.issue, [...path, ...pointer.path]) : [
453
+ {
454
+ path: [...path, ...pointer.path],
455
+ message: missingKey(expectedValue(declared)),
456
+ accepts: nativeKeys(parent)
457
+ }
458
+ ];
459
+ }),
460
+ Match_exports.tag(
461
+ "Composite",
462
+ ({ ast, issues }) => issues.flatMap((issue2) => located(issue2, path, ast))
463
+ ),
464
+ Match_exports.tag("Encoding", (encoding) => located(encoding.issue, path)),
465
+ Match_exports.tag(
466
+ "AnyOf",
467
+ ({ ast, issues }) => issues.length === 0 ? [{ path, message: expectedUnion(ast) }] : issues.flatMap((issue2) => located(issue2, path))
468
+ ),
469
+ Match_exports.orElse((issue2) => {
470
+ const accepts = issue2._tag === "Filter" ? importedSchemaKeys(issue2.filter) : void 0;
471
+ return format(issue2).issues.map((problem) => ({
472
+ path: [
473
+ ...path,
474
+ ...(problem.path ?? []).map((key) => typeof key === "object" ? key.key : key)
475
+ ],
476
+ message: problem.message,
477
+ ...accepts === void 0 ? {} : { accepts }
478
+ }));
479
+ })
480
+ );
481
+ var segment = (key) => typeof key === "number" ? `[${key}]` : typeof key === "string" && echoableKey(key) ? `.${key}` : "[key]";
482
+ var rendered = (path) => `input${path.map(segment).join("")}`;
483
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
484
+ var valueAt = (input, path) => path.reduce(
485
+ (value, key) => Array.isArray(value) && typeof key === "number" ? value[key] : isRecord(value) && typeof key === "string" && Object.hasOwn(value, key) ? value[key] : void 0,
486
+ input
487
+ );
488
+ var spelling = (key) => key.toLowerCase().replace(/[-_]/g, "");
489
+ var suppliedElsewhere = (input, path, accepts) => {
490
+ const key = path.at(-1);
491
+ if (typeof key !== "string" || !echoableKey(key)) return void 0;
492
+ const at = path.slice(0, -1);
493
+ const holder = valueAt(input, at);
494
+ if (!isRecord(holder)) return void 0;
495
+ const candidates = Object.keys(holder).filter((name) => echoableKey(name) && !accepts(name));
496
+ const respelled = candidates.find((name) => name !== key && spelling(name) === spelling(key));
497
+ const deeper = candidates.find((name) => {
498
+ const child = holder[name];
499
+ return isRecord(child) && Object.hasOwn(child, key);
500
+ });
501
+ const found = respelled !== void 0 ? [...at, respelled] : deeper !== void 0 ? [...at, deeper, key] : void 0;
502
+ return found === void 0 ? void 0 : `The input has ${String(found.at(-1))} at ${rendered(found)}; did you mean ${rendered(path)}?`;
503
+ };
504
+ var inputInvalid = (error, input) => {
327
505
  if (!Schema_exports.isSchemaError(error)) return new HostInputInvalid();
328
- const problems = format(error.issue).issues.slice(0, maxInputProblems).map(({ path, message }) => {
329
- const location = (path ?? []).map((key) => segment(typeof key === "object" ? key.key : key));
330
- return `${location.length === 0 ? "input" : `input${location.join("")}`}: ${message}`.slice(
506
+ const problems = located(error.issue, []).slice(0, maxInputProblems).map(({ path, message, accepts }) => {
507
+ const elsewhere = accepts !== void 0 && message.startsWith(missingKeyText) ? suppliedElsewhere(input, path, accepts) : void 0;
508
+ return `${rendered(path)}: ${message}${elsewhere === void 0 ? "" : `. ${elsewhere}`}`.slice(
331
509
  0,
332
510
  512
333
511
  );
@@ -434,7 +612,7 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
434
612
  yield* invoke(hook.unregister, { ...input, state });
435
613
  return null;
436
614
  }
437
- const body = yield* Effect_exports.fromResult(Encoding_exports.decodeBase64(command.request.body)).pipe(
615
+ const body = yield* Effect_exports.fromResult(Base64_exports.decode(command.request.body)).pipe(
438
616
  Effect_exports.mapError(() => new HostInputInvalid())
439
617
  );
440
618
  if (body.byteLength > defaultWebhookTransportLimits.maxBodyBytes)
@@ -467,7 +645,8 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
467
645
  return yield* new HostOutputInvalid();
468
646
  chunks.push(chunk);
469
647
  })
470
- )
648
+ ),
649
+ appCode("webhook")
471
650
  );
472
651
  const bytes = new Uint8Array(size);
473
652
  let offset = 0;
@@ -483,30 +662,437 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
483
662
  () => Schema_exports.decodeUnknownEffect(WebhookResponseData)({
484
663
  status: response.status,
485
664
  headers,
486
- body: Encoding_exports.encodeBase64(new Uint8Array(bytes))
665
+ body: Base64_exports.encode(new Uint8Array(bytes))
487
666
  }),
488
667
  new HostOutputInvalid()
489
668
  );
490
669
  });
491
670
 
671
+ // src/implementation/sql.ts
672
+ var receipts = `${reservedTablePrefix}step_receipts`;
673
+ var stepEvents = `${reservedTablePrefix}step_events`;
674
+ var migrationsTable = `${reservedTablePrefix}migrations`;
675
+ var legacyRows = `${reservedTablePrefix}legacy_rows`;
676
+ var materialize = (cursor) => {
677
+ const rows = cursor.toArray();
678
+ return {
679
+ columnNames: cursor.columnNames,
680
+ rowsRead: cursor.rowsRead,
681
+ rowsWritten: cursor.rowsWritten,
682
+ toArray: () => [...rows],
683
+ one: () => {
684
+ if (rows.length !== 1)
685
+ throw new Error(`Expected exactly one row, but the statement returned ${rows.length}.`);
686
+ return rows[0];
687
+ },
688
+ [Symbol.iterator]: () => rows[Symbol.iterator]()
689
+ };
690
+ };
691
+ var isThenable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
692
+ var missingDatabase = () => {
693
+ throw new Error(
694
+ `This app has no database. Add its first migration, such as ${migrationsDirectory}/0001_create_notes.sql with a CREATE TABLE statement, and deploy again.`
695
+ );
696
+ };
697
+ var noDatabase = { exec: missingDatabase, transaction: missingDatabase };
698
+ var settings = [
699
+ "foreign_keys",
700
+ "defer_foreign_keys",
701
+ "ignore_check_constraints",
702
+ "legacy_alter_table",
703
+ "recursive_triggers",
704
+ "reverse_unordered_selects"
705
+ ];
706
+ var readSettings = (storage) => new Map(
707
+ settings.map((name) => [name, Number(storage.sql.exec(`PRAGMA ${name}`).toArray()[0]?.[name])])
708
+ );
709
+ var changedSetting = (storage, baseline) => {
710
+ const current = readSettings(storage);
711
+ return settings.find((name) => current.get(name) !== baseline.get(name));
712
+ };
713
+ var restoreSettings = (storage, baseline) => {
714
+ const current = readSettings(storage);
715
+ for (const [name, value] of baseline)
716
+ if (current.get(name) !== value) storage.sql.exec(`PRAGMA ${name} = ${value}`);
717
+ storage.sql.exec("PRAGMA case_sensitive_like = OFF");
718
+ };
719
+ var ReadRolledBack = class extends Error {
720
+ };
721
+ var authorSql = (storage, options) => {
722
+ let closed = false;
723
+ const live = () => {
724
+ if (closed || options.signal.aborted)
725
+ throw new Error("This call has ended, so its ctx.sql no longer runs statements.");
726
+ };
727
+ let open = false;
728
+ let transactions = 0;
729
+ const baseline = readSettings(storage);
730
+ const checkSettings = () => {
731
+ const changed = changedSetting(storage, baseline);
732
+ if (changed !== void 0)
733
+ throw refuse(
734
+ new Error(
735
+ `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.`
736
+ )
737
+ );
738
+ };
739
+ const changes = () => Number(storage.sql.exec("SELECT total_changes() AS n").toArray()[0]?.n);
740
+ let violation;
741
+ const refuse = (error) => {
742
+ if (open) violation ??= error;
743
+ return error;
744
+ };
745
+ const run = (query, bindings, mode) => {
746
+ try {
747
+ return runStatement(query, bindings, mode);
748
+ } finally {
749
+ restoreSettings(storage, baseline);
750
+ }
751
+ };
752
+ const runStatement = (query, bindings, mode) => {
753
+ live();
754
+ if (bindings.length > sqlBindingsLimit)
755
+ throw refuse(
756
+ new Error(
757
+ `A statement can bind at most ${sqlBindingsLimit} values, but this one binds ${bindings.length}. Pass a long list as one JSON array and read it with json_each(?), or split the work into batches.`
758
+ )
759
+ );
760
+ if (mode === "write") {
761
+ const statement = () => {
762
+ const cursor = materialize(storage.sql.exec(query, ...bindings));
763
+ checkSettings();
764
+ return cursor;
765
+ };
766
+ if (!open) return storage.transactionSync(statement);
767
+ try {
768
+ return statement();
769
+ } catch (error) {
770
+ refuse(error instanceof Error ? error : new Error(String(error)));
771
+ throw error;
772
+ }
773
+ }
774
+ if (open) {
775
+ return runStatement(query, bindings, "write");
776
+ }
777
+ const before = changes();
778
+ let read;
779
+ let changed = false;
780
+ try {
781
+ storage.transactionSync(() => {
782
+ read = materialize(storage.sql.exec(query, ...bindings));
783
+ changed = changes() !== before;
784
+ checkSettings();
785
+ throw new ReadRolledBack();
786
+ });
787
+ } catch (error) {
788
+ if (!(error instanceof ReadRolledBack)) throw error;
789
+ }
790
+ if (changed || read === void 0)
791
+ throw new Error(
792
+ 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."
793
+ );
794
+ return read;
795
+ };
796
+ const reader = {
797
+ exec: (query, ...bindings) => run(query, bindings, "read")
798
+ };
799
+ const transactionHandle = () => {
800
+ let active = true;
801
+ const tx = {
802
+ exec: (query, ...bindings) => {
803
+ if (!active)
804
+ throw new Error("This transaction has ended, so its tx no longer runs statements.");
805
+ return run(query, bindings, "write");
806
+ }
807
+ };
808
+ return {
809
+ tx,
810
+ end: () => {
811
+ active = false;
812
+ }
813
+ };
814
+ };
815
+ const transaction = (work) => {
816
+ live();
817
+ if (open) throw new Error("ctx.sql.transaction(...) cannot be nested.");
818
+ const step = options.step;
819
+ if (step !== void 0 && transactions > 0)
820
+ throw new Error(
821
+ "A workflow step mutation opens at most one ctx.sql.transaction(...), which records the step's result."
822
+ );
823
+ transactions += 1;
824
+ violation = void 0;
825
+ const handle = transactionHandle();
826
+ const emittedBefore = options.emitted?.length;
827
+ const discardEmitted = () => {
828
+ if (options.emitted !== void 0 && emittedBefore !== void 0)
829
+ options.emitted.length = emittedBefore;
830
+ };
831
+ const body = () => {
832
+ open = true;
833
+ try {
834
+ const complete = () => {
835
+ const value = work(handle.tx);
836
+ if (isThenable(value))
837
+ throw new Error(
838
+ "ctx.sql.transaction(...) callbacks are synchronous and cannot await. Call outside services before or after the transaction."
839
+ );
840
+ if (violation !== void 0) throw violation;
841
+ return value;
842
+ };
843
+ if (step === void 0) return complete();
844
+ storage.sql.exec(
845
+ `CREATE TABLE IF NOT EXISTS ${receipts} (id TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, result TEXT NOT NULL) WITHOUT ROWID`
846
+ );
847
+ const saved = storage.sql.exec(`SELECT fingerprint, result FROM ${receipts} WHERE id = ?`, step.key).toArray()[0];
848
+ storage.sql.exec(
849
+ `CREATE TABLE IF NOT EXISTS ${stepEvents} (id TEXT PRIMARY KEY, events TEXT NOT NULL) WITHOUT ROWID`
850
+ );
851
+ if (saved !== void 0) {
852
+ if (saved.fingerprint !== step.fingerprint)
853
+ throw new Error("This workflow step already ran with different input.");
854
+ const replayed = storage.sql.exec(`SELECT events FROM ${stepEvents} WHERE id = ?`, step.key).toArray()[0];
855
+ if (replayed !== void 0 && options.emitted !== void 0)
856
+ options.emitted.push(...JSON.parse(String(replayed.events)));
857
+ return JSON.parse(String(saved.result));
858
+ }
859
+ const encoded = JSON.stringify(complete() ?? null);
860
+ const emitted = options.emitted?.slice(emittedBefore ?? 0) ?? [];
861
+ if (emitted.length > 0)
862
+ storage.sql.exec(
863
+ `INSERT INTO ${stepEvents} (id, events) VALUES (?, ?)`,
864
+ step.key,
865
+ JSON.stringify(emitted)
866
+ );
867
+ storage.sql.exec(
868
+ `INSERT INTO ${receipts} (id, fingerprint, result) VALUES (?, ?, ?)`,
869
+ step.key,
870
+ step.fingerprint,
871
+ encoded
872
+ );
873
+ return JSON.parse(encoded);
874
+ } finally {
875
+ open = false;
876
+ handle.end();
877
+ }
878
+ };
879
+ try {
880
+ return storage.transactionSync(body);
881
+ } catch (error) {
882
+ discardEmitted();
883
+ throw error;
884
+ }
885
+ };
886
+ const writer = {
887
+ // A step's writes go through its one transaction, which also records its receipt.
888
+ exec: (query, ...bindings) => run(query, bindings, options.step ? "read" : "write"),
889
+ transaction
890
+ };
891
+ return {
892
+ reader,
893
+ writer,
894
+ close: () => {
895
+ closed = true;
896
+ }
897
+ };
898
+ };
899
+ var MigrationFileInvalid = class extends Schema_exports.TaggedError()(
900
+ "MigrationFileInvalid",
901
+ { path: Schema_exports.String, reason: Schema_exports.String }
902
+ ) {
903
+ get message() {
904
+ return `${this.path}: ${this.reason}`;
905
+ }
906
+ };
907
+ var MigrationHistoryChanged = class extends Schema_exports.TaggedError()(
908
+ "MigrationHistoryChanged",
909
+ { reason: Schema_exports.String }
910
+ ) {
911
+ get message() {
912
+ 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.`;
913
+ }
914
+ };
915
+ var MigrationFailed = class extends Schema_exports.TaggedError()("MigrationFailed", {
916
+ path: Schema_exports.String,
917
+ reason: Schema_exports.String
918
+ }) {
919
+ get message() {
920
+ return `${this.path} failed: ${this.reason}. No migrations were applied; the previous deployment is still active.`;
921
+ }
922
+ };
923
+ var migrationName = /^(\d+)_[A-Za-z0-9_-]+\.sql$/;
924
+ var sha256 = (text) => (
925
+ // oxlint-disable-next-line executor/authored-code-through-adapter -- Web Crypto
926
+ Effect_exports.promise(() => crypto.subtle.digest("SHA-256", new TextEncoder().encode(text))).pipe(
927
+ Effect_exports.map(
928
+ (digest) => Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")
929
+ )
930
+ )
931
+ );
932
+ var statementsOf = (script) => {
933
+ let end = 0;
934
+ let index = 0;
935
+ while (index < script.length) {
936
+ const char = script[index];
937
+ const next = script[index + 1];
938
+ if (char === "-" && next === "-") {
939
+ const newline = script.indexOf("\n", index);
940
+ index = newline === -1 ? script.length : newline + 1;
941
+ continue;
942
+ }
943
+ if (char === "/" && next === "*") {
944
+ const close = script.indexOf("*/", index + 2);
945
+ index = close === -1 ? script.length : close + 2;
946
+ continue;
947
+ }
948
+ const closing = char === "'" || char === '"' || char === "`" ? char : char === "[" ? "]" : void 0;
949
+ if (closing !== void 0) {
950
+ let after = index + 1;
951
+ while (true) {
952
+ const found = script.indexOf(closing, after);
953
+ if (found === -1) {
954
+ after = script.length;
955
+ break;
956
+ }
957
+ if (closing !== "]" && script[found + 1] === closing) {
958
+ after = found + 2;
959
+ continue;
960
+ }
961
+ after = found + 1;
962
+ break;
963
+ }
964
+ index = after;
965
+ end = index;
966
+ continue;
967
+ }
968
+ index += 1;
969
+ if (char !== void 0 && !/\s/u.test(char)) end = index;
970
+ }
971
+ return script.slice(0, end);
972
+ };
973
+ var hasMigrations = (files) => files.some(
974
+ (file) => file.path.startsWith(`${migrationsDirectory}/`) && file.path.endsWith(".sql")
975
+ );
976
+ var migrationsOf = (files) => Effect_exports.gen(function* () {
977
+ const found = [];
978
+ for (const file of files) {
979
+ if (!file.path.startsWith(`${migrationsDirectory}/`) || !file.path.endsWith(".sql")) continue;
980
+ const name = file.path.slice(migrationsDirectory.length + 1);
981
+ const match = migrationName.exec(name);
982
+ if (name.includes("/") || match === null)
983
+ return yield* new MigrationFileInvalid({
984
+ path: file.path,
985
+ reason: "migrations are files directly in migrations/ named like 0001_create_notes.sql: a number that orders them, an underscore, then a name."
986
+ });
987
+ const content = file.content.replaceAll("\r\n", "\n");
988
+ found.push({
989
+ path: file.path,
990
+ order: Number(match[1]),
991
+ content,
992
+ hash: yield* sha256(content)
993
+ });
994
+ }
995
+ const ordered = [...found].sort((left, right) => left.order - right.order);
996
+ for (const [index, migration] of ordered.entries()) {
997
+ const previous = ordered[index - 1];
998
+ if (previous !== void 0 && previous.order === migration.order)
999
+ return yield* new MigrationFileInvalid({
1000
+ path: migration.path,
1001
+ reason: `it has the same number as ${previous.path}; give each migration its own number.`
1002
+ });
1003
+ }
1004
+ return ordered;
1005
+ });
1006
+ var History = Schema_exports.Array(
1007
+ Schema_exports.Struct({ id: Schema_exports.Number, path: Schema_exports.String, hash: Schema_exports.String })
1008
+ );
1009
+ var migrate = (storage, files) => Effect_exports.gen(function* () {
1010
+ const migrations = yield* migrationsOf(files);
1011
+ const baseline = readSettings(storage);
1012
+ return yield* Effect_exports.sync(
1013
+ () => storage.transactionSync(() => {
1014
+ storage.sql.exec(
1015
+ `CREATE TABLE IF NOT EXISTS ${migrationsTable} (id INTEGER PRIMARY KEY, path TEXT NOT NULL, hash TEXT NOT NULL, applied_at TEXT NOT NULL)`
1016
+ );
1017
+ const stored = storage.sql.exec("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'app_rows'").toArray().length > 0;
1018
+ storage.sql.exec(`DROP VIEW IF EXISTS ${legacyRows}`);
1019
+ storage.sql.exec(
1020
+ `CREATE VIEW ${legacyRows} (table_name, id, body) AS ${stored ? "SELECT table_name, id, body FROM app_rows" : "SELECT '', '', '' WHERE 0"}`
1021
+ );
1022
+ const history = Schema_exports.decodeUnknownSync(History)(
1023
+ storage.sql.exec(`SELECT id, path, hash FROM ${migrationsTable} ORDER BY id`).toArray()
1024
+ );
1025
+ for (const [index, applied] of history.entries()) {
1026
+ const current = migrations[index];
1027
+ if (current === void 0)
1028
+ throw new MigrationHistoryChanged({
1029
+ reason: `${applied.path} was applied to this app's database but is no longer in migrations/.`
1030
+ });
1031
+ if (current.path !== applied.path)
1032
+ throw new MigrationHistoryChanged({
1033
+ reason: `Migration ${index + 1} was applied as ${applied.path}, but the build has ${current.path} in its place.`
1034
+ });
1035
+ if (current.hash !== applied.hash)
1036
+ throw new MigrationHistoryChanged({
1037
+ reason: `${applied.path} changed after it was applied to this app's database.`
1038
+ });
1039
+ }
1040
+ const pending = migrations.slice(history.length);
1041
+ const appliedAt = (/* @__PURE__ */ new Date()).toISOString();
1042
+ for (const [offset, migration] of pending.entries()) {
1043
+ const statements = statementsOf(migration.content);
1044
+ try {
1045
+ if (statements !== "") storage.sql.exec(statements);
1046
+ } catch (error) {
1047
+ throw new MigrationFailed({
1048
+ path: migration.path,
1049
+ reason: error instanceof Error ? error.message : String(error)
1050
+ });
1051
+ }
1052
+ storage.sql.exec(
1053
+ `INSERT INTO ${migrationsTable} (id, path, hash, applied_at) VALUES (?, ?, ?, ?)`,
1054
+ history.length + offset + 1,
1055
+ migration.path,
1056
+ migration.hash,
1057
+ appliedAt
1058
+ );
1059
+ }
1060
+ return pending.map((migration, offset) => ({
1061
+ id: history.length + offset + 1,
1062
+ name: migration.path
1063
+ }));
1064
+ })
1065
+ ).pipe(
1066
+ // Both are thrown inside the transaction so that it rolls back; they are expected failures.
1067
+ Effect_exports.catchDefect(
1068
+ (defect) => Schema_exports.is(MigrationFailed)(defect) || Schema_exports.is(MigrationHistoryChanged)(defect) ? Effect_exports.fail(defect) : Effect_exports.die(defect)
1069
+ ),
1070
+ Effect_exports.ensuring(Effect_exports.sync(() => restoreSettings(storage, baseline)))
1071
+ );
1072
+ });
1073
+
492
1074
  // src/implementation/cache.ts
493
1075
  var unavailableCache = {
494
1076
  transport: () => Effect_exports.fail(new CacheError({ reason: "unavailable" })),
495
1077
  background: () => Effect_exports.die(new Error("Cache background runner is unavailable"))
496
1078
  };
497
- var authorCache = (host, accounts, signal, deadline) => {
1079
+ var authorCache = (host, accounts, signal, telemetry, deadline) => {
498
1080
  const scoped = (scope, callerSignal = signal) => {
499
1081
  const cache = makeCache(host.transport, host.background, scope, deadline);
500
- const load = (method, options) => cache[method]({
1082
+ const load = (read, options) => cache[read]({
501
1083
  key: options.key,
502
1084
  schema: decoderOf(options.schema),
503
1085
  freshFor: options.freshFor,
504
1086
  ...options.staleFor === void 0 ? {} : { staleFor: options.staleFor },
1087
+ ...options.stale === void 0 ? {} : { stale: options.stale },
505
1088
  load: Effect_exports.acquireUseRelease(
506
1089
  Effect_exports.sync(() => new AbortController()),
507
- (controller) => invocationFetch(controller.signal).pipe(
1090
+ (controller) => appInvocationFetch(controller.signal).pipe(
508
1091
  Effect_exports.flatMap(
509
- (fetch) => fromPromise(options.load)({
1092
+ (fetch) => fromPromise(
1093
+ method(options, "load"),
1094
+ "loader"
1095
+ )({
510
1096
  fetch,
511
1097
  signal: controller.signal,
512
1098
  cache: scoped(scope, controller.signal)
@@ -516,22 +1102,30 @@ var authorCache = (host, accounts, signal, deadline) => {
516
1102
  (controller) => Effect_exports.sync(() => controller.abort())
517
1103
  )
518
1104
  });
1105
+ const service = (method2, operation) => toPromise(
1106
+ (...args) => operation(...args).pipe(
1107
+ owned("executor", "app.cache.call", { attributes: { "cache.method": method2 } })
1108
+ ),
1109
+ callerSignal,
1110
+ telemetry
1111
+ );
519
1112
  return {
520
- get: toPromise((options) => load("get", options), callerSignal),
521
- revalidate: toPromise(
522
- (options) => load("revalidate", options),
523
- callerSignal
1113
+ get: service("get", (options) => load("get", options)),
1114
+ revalidate: service(
1115
+ "revalidate",
1116
+ (options) => load("revalidate", options)
524
1117
  ),
525
- read: toPromise(
1118
+ read: service(
1119
+ "read",
526
1120
  (key, schema) => cache.read([key]).pipe(
527
1121
  Effect_exports.flatMap((entries) => {
528
1122
  const entry = entries[0];
529
1123
  return entry === void 0 || entry === null ? Effect_exports.succeed(void 0) : Schema_exports.decodeUnknownEffect(decoderOf(schema))(entry.value);
530
1124
  })
531
- ),
532
- callerSignal
1125
+ )
533
1126
  ),
534
- readMany: toPromise(
1127
+ readMany: service(
1128
+ "readMany",
535
1129
  (keys, schema) => cache.read(keys).pipe(
536
1130
  Effect_exports.flatMap(
537
1131
  (entries) => Effect_exports.forEach(
@@ -539,11 +1133,10 @@ var authorCache = (host, accounts, signal, deadline) => {
539
1133
  (entry) => entry === null ? Effect_exports.succeed(void 0) : Schema_exports.decodeUnknownEffect(decoderOf(schema))(entry.value)
540
1134
  )
541
1135
  )
542
- ),
543
- callerSignal
1136
+ )
544
1137
  ),
545
- write: toPromise(cache.write, callerSignal),
546
- invalidate: toPromise(cache.invalidate, callerSignal),
1138
+ write: service("write", cache.write),
1139
+ invalidate: service("invalidate", cache.invalidate),
547
1140
  forAccount: (account) => {
548
1141
  const bound = Object.values(accounts).flatMap((value) => Array.isArray(value) ? value : [value]).find((value) => value.id === account.id);
549
1142
  if (bound === void 0) throw new CacheError({ reason: "invalid" });
@@ -575,9 +1168,9 @@ var evaluationSafe = (work, secrets) => work.pipe(
575
1168
  const error = Cause_exports.squash(cause);
576
1169
  const provider = parseProviderError(error);
577
1170
  const skills = parseSkillLoadFailed(error);
578
- const mcp = parseMcpError(error);
1171
+ const mcp = parseMcpError(error, secrets);
579
1172
  return Effect_exports.fail(
580
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed(failureDetail(error, secrets))
1173
+ 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))
581
1174
  );
582
1175
  })
583
1176
  );
@@ -594,37 +1187,52 @@ var declarationSafe = (work, summary) => Effect_exports.suspend(work).pipe(
594
1187
  (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(declarationInvalid(summary, Cause_exports.squash(cause)))
595
1188
  )
596
1189
  );
1190
+ function declaredExposure(exposure) {
1191
+ const named = (kind) => Object.entries(exposure ?? {}).filter(([, value]) => value === kind).map(([field]) => field).sort();
1192
+ const plain = named("plain");
1193
+ const raw = named("raw");
1194
+ return { ...plain.length === 0 ? {} : { plain }, ...raw.length === 0 ? {} : { raw } };
1195
+ }
1196
+ function declaredPlacements(request) {
1197
+ return request === void 0 || request.length === 0 ? {} : { request: normalizePlacements(request) };
1198
+ }
597
1199
  function providerDeclaration(provider) {
598
1200
  return declarationSafe(
599
1201
  () => Effect_exports.gen(function* () {
600
1202
  const auth = /* @__PURE__ */ new Map();
601
- for (const [name, method] of Object.entries(provider.auth)) {
602
- switch (method._tag) {
1203
+ for (const [name, method2] of Object.entries(provider.auth)) {
1204
+ switch (method2._tag) {
603
1205
  case "secrets":
604
1206
  auth.set(name, {
605
1207
  type: "secrets",
606
- label: method.label,
607
- fields: yield* jsonSchemaDocument(method.fields)
1208
+ label: method2.label,
1209
+ fields: yield* jsonSchemaDocument(method2.fields),
1210
+ ...declaredExposure(method2.exposure),
1211
+ ...declaredPlacements(method2.request)
608
1212
  });
609
1213
  break;
610
1214
  case "oauth2":
611
1215
  auth.set(name, {
612
1216
  type: "oauth2",
613
- ...method.config,
614
- response: yield* jsonSchemaDocument(method.response)
1217
+ ...method2.config,
1218
+ response: yield* jsonSchemaDocument(method2.response),
1219
+ ...declaredExposure(method2.exposure),
1220
+ ...declaredPlacements(method2.request)
615
1221
  });
616
1222
  break;
617
1223
  }
618
1224
  }
619
1225
  return yield* Schema_exports.decodeUnknownEffect(DeclaredProvider)({
620
1226
  name: provider.name,
621
- auth: Object.fromEntries(auth)
1227
+ auth: Object.fromEntries(auth),
1228
+ // Order and repetition carry no meaning, so neither changes the provider's identity.
1229
+ ...provider.hosts === void 0 ? {} : { hosts: [...new Set(provider.hosts)].sort() }
622
1230
  });
623
1231
  }),
624
1232
  `Account provider "${provider.name}" has an invalid declaration`
625
1233
  );
626
1234
  }
627
- function requirements(slots, database) {
1235
+ function requirements(slots, sql, events) {
628
1236
  return Effect_exports.gen(function* () {
629
1237
  const accounts = /* @__PURE__ */ new Map();
630
1238
  for (const [slot, selection] of Object.entries(slots)) {
@@ -638,10 +1246,16 @@ function requirements(slots, database) {
638
1246
  return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
639
1247
  accounts: Object.fromEntries(accounts),
640
1248
  capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
641
- ...database === void 0 ? {} : { database }
1249
+ ...sql ? { sql: true } : {},
1250
+ ...events === void 0 || Object.keys(events).length === 0 ? {} : {
1251
+ events: yield* declarationSafe(
1252
+ () => declaredEvents(events),
1253
+ "The app's event declarations are invalid"
1254
+ )
1255
+ }
642
1256
  }).pipe(
643
1257
  Effect_exports.mapError(
644
- (cause) => declarationInvalid("The app's account or database declarations are invalid", cause)
1258
+ (cause) => declarationInvalid("The app's account declarations are invalid", cause)
645
1259
  )
646
1260
  );
647
1261
  });
@@ -653,6 +1267,17 @@ function canonical(value) {
653
1267
  }
654
1268
  return JSON.stringify(value);
655
1269
  }
1270
+ function withoutGrants({ hosts: _hosts, ...provider }) {
1271
+ return {
1272
+ ...provider,
1273
+ auth: Object.fromEntries(
1274
+ Object.entries(provider.auth).map(([name, { request: _request, ...method2 }]) => [
1275
+ name,
1276
+ method2
1277
+ ])
1278
+ )
1279
+ };
1280
+ }
656
1281
  function bindAccounts(slots, declarations, context) {
657
1282
  return safe2(
658
1283
  () => Effect_exports.gen(function* () {
@@ -678,14 +1303,17 @@ function bindAccounts(slots, declarations, context) {
678
1303
  for (const account of accounts) {
679
1304
  if (ids.has(account.id)) return yield* Effect_exports.fail(new HostAccountsInvalid());
680
1305
  ids.add(account.id);
681
- if (canonical(account.provider) !== canonical(requirement.definition) || !Object.hasOwn(provider.auth, account.method))
1306
+ if (canonical(withoutGrants(account.provider)) !== canonical(withoutGrants(requirement.definition)) || !Object.hasOwn(provider.auth, account.method))
682
1307
  return yield* Effect_exports.fail(new HostAccountsInvalid());
683
- const method = provider.auth[account.method];
684
- if (method === void 0) return yield* Effect_exports.fail(new HostAccountsInvalid());
1308
+ const method2 = provider.auth[account.method];
1309
+ if (method2 === void 0) return yield* Effect_exports.fail(new HostAccountsInvalid());
685
1310
  const fields = yield* Schema_exports.decodeUnknownEffect(
686
- method._tag === "secrets" ? method.fields : method.response
1311
+ method2._tag === "secrets" ? method2.fields : method2.response
687
1312
  )(account.fields);
688
- values.push({ id: account.id, method: account.method, fields });
1313
+ const granted = Object.hasOwn(account.provider.auth, account.method) ? account.provider.auth[account.method]?.request : void 0;
1314
+ values.push(
1315
+ withPlacements({ id: account.id, method: account.method, fields }, granted)
1316
+ );
689
1317
  }
690
1318
  if (many) bound.set(slot, values);
691
1319
  else {
@@ -699,7 +1327,42 @@ function bindAccounts(slots, declarations, context) {
699
1327
  new HostAccountsInvalid()
700
1328
  );
701
1329
  }
702
- function dispatch(app, request, context, signal) {
1330
+ var fetchLifetime = (signal, background) => Effect_exports.acquireRelease(
1331
+ Effect_exports.sync(() => {
1332
+ const controller = new AbortController();
1333
+ let refreshes = 0;
1334
+ let ended = false;
1335
+ const settle = () => {
1336
+ if (ended && refreshes === 0) controller.abort();
1337
+ };
1338
+ const end = () => {
1339
+ ended = true;
1340
+ settle();
1341
+ };
1342
+ signal.addEventListener("abort", end, { once: true });
1343
+ if (signal.aborted) end();
1344
+ const settled = Effect_exports.sync(() => {
1345
+ refreshes -= 1;
1346
+ settle();
1347
+ });
1348
+ return {
1349
+ signal: controller.signal,
1350
+ close: () => {
1351
+ signal.removeEventListener("abort", end);
1352
+ end();
1353
+ },
1354
+ /** Counted from the hand-off, so a refresh that has not started yet keeps the fetch. */
1355
+ background: (task) => Effect_exports.suspend(() => {
1356
+ refreshes += 1;
1357
+ return background(task.pipe(Effect_exports.ensuring(settled))).pipe(
1358
+ Effect_exports.onError(() => settled)
1359
+ );
1360
+ })
1361
+ };
1362
+ }),
1363
+ (lifetime) => Effect_exports.sync(lifetime.close)
1364
+ );
1365
+ function dispatch(app, request, context, signal, emitted) {
703
1366
  return Effect_exports.scoped(
704
1367
  Effect_exports.gen(function* () {
705
1368
  if (!isApp(app))
@@ -708,28 +1371,52 @@ function dispatch(app, request, context, signal) {
708
1371
  );
709
1372
  const native = toEffectApp(app);
710
1373
  const secrets = accountSecrets(context.accounts);
711
- const storageFailure = (error) => Effect_exports.fail(new HostOperationFailed(failureDetail(error, secrets)));
712
- const declared = yield* requirements(native.accounts, native.database?.schema);
713
- if (request.operation === "requirements") {
714
- if (native.database !== void 0)
715
- yield* parseDatabaseSchema(native.database.schema).pipe(
716
- Effect_exports.catchTag(
717
- "AppDatabaseError",
718
- (cause) => Effect_exports.fail(
719
- declarationInvalid("The app's account or database declarations are invalid", cause)
720
- )
721
- )
722
- );
1374
+ const ownsSql = hasMigrations(context.files ?? []);
1375
+ const declared = yield* requirements(native.accounts, ownsSql, native.events);
1376
+ if (request.operation === "requirements")
723
1377
  return yield* safe2(
724
1378
  () => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
725
1379
  new HostDeclarationInvalid()
726
1380
  );
1381
+ if (request.operation === "migrate") {
1382
+ if (!ownsSql) return yield* new HostOperationNotFound();
1383
+ const storage2 = context.storage;
1384
+ if (storage2 === void 0)
1385
+ return yield* new HostOperationFailed(
1386
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1387
+ );
1388
+ const sources = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(SkillFile))(
1389
+ context.files ?? []
1390
+ ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1391
+ const applied = yield* migrate(storage2, sources).pipe(
1392
+ Effect_exports.mapError((error) => new HostOperationFailed(failureDetail(error, secrets))),
1393
+ Effect_exports.withSpan("app.sql.migrate")
1394
+ );
1395
+ return yield* safe2(
1396
+ () => Schema_exports.decodeUnknownEffect(JsonValue)(applied),
1397
+ new HostOutputInvalid()
1398
+ );
727
1399
  }
728
1400
  const lifetime = yield* Effect_exports.acquireRelease(
729
1401
  Effect_exports.sync(() => new AbortController()),
730
1402
  (controller) => Effect_exports.sync(() => controller.abort())
731
1403
  );
732
1404
  const invocationSignal = AbortSignal.any([signal, lifetime.signal]);
1405
+ const storage = context.storage;
1406
+ const sqlSession = (step) => !ownsSql ? Effect_exports.succeed({ reader: noDatabase, writer: noDatabase }) : storage === void 0 ? Effect_exports.fail(
1407
+ new HostOperationFailed(
1408
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1409
+ )
1410
+ ) : Effect_exports.acquireRelease(
1411
+ Effect_exports.sync(
1412
+ () => authorSql(storage, {
1413
+ signal: invocationSignal,
1414
+ emitted,
1415
+ ...step === void 0 ? {} : { step }
1416
+ })
1417
+ ),
1418
+ (session2) => Effect_exports.sync(session2.close)
1419
+ );
733
1420
  const deadline = context.deadline === void 0 ? void 0 : yield* safe2(
734
1421
  () => Schema_exports.decodeUnknownEffect(InvocationDeadline)(context.deadline),
735
1422
  new HostInputInvalid()
@@ -756,33 +1443,56 @@ function dispatch(app, request, context, signal) {
756
1443
  declared,
757
1444
  request.requirement,
758
1445
  context,
759
- invocationSignal
1446
+ invocationSignal,
1447
+ deadline
760
1448
  ).pipe(withinDeadline);
761
1449
  let running;
762
- let transactionOpen = false;
763
1450
  const delivery = (request2, signal2) => Effect_exports.suspend(
764
- () => transactionOpen ? Effect_exports.fail(new ElicitationFailed({ reason: "transaction" })) : running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
765
- Effect_exports.withSpan("app.tool.elicitation"),
1451
+ () => running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
1452
+ // Delivering the question and waiting for its answer is the person's time.
1453
+ owned("person", "app.tool.elicitation"),
766
1454
  Effect_exports.provideContext(running.context)
767
1455
  ) : Effect_exports.fail(new ElicitationFailed({ reason: "unavailable" }))
768
1456
  );
769
1457
  const unavailableWorkflow = () => Effect_exports.fail(new WorkflowFailure({ reason: "unavailable", retryable: false }));
1458
+ const telemetry = yield* captureTelemetry;
1459
+ const control = (operation, work) => work.pipe(
1460
+ owned("executor", workflowControlSpan, {
1461
+ attributes: { "executor.workflow.operation": operation }
1462
+ })
1463
+ );
770
1464
  const workflowControls = {
771
1465
  start: toPromise(
772
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.start(input2),
773
- invocationSignal
1466
+ (input2) => control(
1467
+ "start",
1468
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.start(input2)
1469
+ ),
1470
+ invocationSignal,
1471
+ telemetry.context
774
1472
  ),
775
1473
  get: toPromise(
776
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.get(input2),
777
- invocationSignal
1474
+ (input2) => control(
1475
+ "get",
1476
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.get(input2)
1477
+ ),
1478
+ invocationSignal,
1479
+ telemetry.context
778
1480
  ),
779
1481
  list: toPromise(
780
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.list(input2),
781
- invocationSignal
1482
+ (input2) => control(
1483
+ "list",
1484
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.list(input2)
1485
+ ),
1486
+ invocationSignal,
1487
+ telemetry.context
782
1488
  ),
783
1489
  terminate: toPromise(
784
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.terminate(input2),
785
- invocationSignal
1490
+ (input2) => control(
1491
+ "terminate",
1492
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.terminate(input2)
1493
+ ),
1494
+ invocationSignal,
1495
+ telemetry.context
786
1496
  )
787
1497
  };
788
1498
  const workflowReads = {
@@ -794,6 +1504,7 @@ function dispatch(app, request, context, signal) {
794
1504
  ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
795
1505
  let cacheCommands = 0;
796
1506
  const hostCache = context.cache ?? unavailableCache;
1507
+ const fetching = yield* fetchLifetime(signal, hostCache.background);
797
1508
  const bound = {
798
1509
  cache: authorCache(
799
1510
  {
@@ -801,10 +1512,12 @@ function dispatch(app, request, context, signal) {
801
1512
  transport: (command) => {
802
1513
  cacheCommands += 1;
803
1514
  return hostCache.transport(command);
804
- }
1515
+ },
1516
+ background: fetching.background
805
1517
  },
806
1518
  Redacted_exports.value(context.accounts),
807
1519
  invocationSignal,
1520
+ telemetry.context,
808
1521
  deadline
809
1522
  ),
810
1523
  files,
@@ -813,9 +1526,20 @@ function dispatch(app, request, context, signal) {
813
1526
  ),
814
1527
  workflows: workflowReads,
815
1528
  signal: invocationSignal,
816
- fetch: yield* invocationFetch(invocationSignal),
817
- elicit: makeElicit(delivery, invocationSignal)
1529
+ fetch: yield* appInvocationFetch(fetching.signal),
1530
+ elicit: makeElicit(delivery, invocationSignal, telemetry.context)
818
1531
  };
1532
+ const accountIds = Object.values(bound.accounts).flatMap(
1533
+ (selected) => (Array.isArray(selected) ? selected : [selected]).map(
1534
+ (account) => account.id
1535
+ )
1536
+ );
1537
+ const emitter = (sourceAccount) => makeEmitter({
1538
+ events: native.events ?? {},
1539
+ accounts: accountIds,
1540
+ ...sourceAccount === void 0 ? {} : { sourceAccount },
1541
+ emitted
1542
+ });
819
1543
  const definition = yield* evaluationSafe(native.evaluate(bound), secrets).pipe(
820
1544
  Effect_exports.withSpan("app.evaluate")
821
1545
  );
@@ -887,10 +1611,11 @@ function dispatch(app, request, context, signal) {
887
1611
  cache: authorCache(
888
1612
  context.cache ?? unavailableCache,
889
1613
  Redacted_exports.value(current.accounts),
890
- signal2
1614
+ signal2,
1615
+ (yield* captureTelemetry).context
891
1616
  ),
892
1617
  files,
893
- fetch: yield* invocationFetch(signal2),
1618
+ fetch: yield* appInvocationFetch(signal2),
894
1619
  signal: signal2,
895
1620
  runId: execution.runId,
896
1621
  stepId,
@@ -938,7 +1663,8 @@ function dispatch(app, request, context, signal) {
938
1663
  );
939
1664
  }
940
1665
  if (request.operation === "webhook-complete" || request.operation === "webhook-validate" || request.operation === "webhooks" || request.operation === "webhook-register" || request.operation === "webhook-handle" || request.operation === "webhook-unregister") {
941
- const executeWebhook = (db) => dispatchWebhook(
1666
+ const session2 = yield* sqlSession();
1667
+ return yield* dispatchWebhook(
942
1668
  definition,
943
1669
  request,
944
1670
  {
@@ -948,27 +1674,17 @@ function dispatch(app, request, context, signal) {
948
1674
  workflows: workflowControls,
949
1675
  signal: bound.signal,
950
1676
  fetch: bound.fetch,
951
- ...db === void 0 || native.database === void 0 ? {} : {
952
- db: authorDatabase(native.database.tables, db, invocationSignal, true)
953
- }
1677
+ sql: session2.writer,
1678
+ events: emitter("sourceAccount" in request ? request.sourceAccount : void 0)
954
1679
  },
955
1680
  Redacted_exports.value(context.accounts)
956
1681
  );
957
- if (native.database === void 0 || !["webhook-register", "webhook-handle", "webhook-unregister"].includes(request.operation))
958
- return yield* executeWebhook();
959
- const storage2 = context.storage ?? unavailableStorage;
960
- return yield* storage2.mutate(native.database.schema, executeWebhook).pipe(
961
- Effect_exports.catchTags({
962
- AppDatabaseError: storageFailure,
963
- DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
964
- AppStorageUnavailable: storageFailure,
965
- AppStorageError: storageFailure
966
- })
967
- );
968
1682
  }
969
1683
  const toolName = request.operation === "call" ? request.tool : request.name;
970
1684
  const location = locate(definition.tools, toolName);
971
- const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets);
1685
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets).pipe(
1686
+ Effect_exports.withSpan("app.tool.resolve")
1687
+ );
972
1688
  if (tool === void 0)
973
1689
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
974
1690
  const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
@@ -979,7 +1695,7 @@ function dispatch(app, request, context, signal) {
979
1695
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
980
1696
  ).pipe(
981
1697
  Effect_exports.catchCause(
982
- (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(inputInvalid(Cause_exports.squash(cause)))
1698
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(inputInvalid(Cause_exports.squash(cause), request.input))
983
1699
  )
984
1700
  );
985
1701
  if (context.approval !== void 0) {
@@ -1024,24 +1740,23 @@ function dispatch(app, request, context, signal) {
1024
1740
  Match_exports.exhaustive
1025
1741
  );
1026
1742
  }
1027
- const execute = (db) => Effect_exports.gen(function* () {
1028
- transactionOpen = db !== void 0;
1743
+ const replay = context.replay === void 0 ? void 0 : yield* safe2(
1744
+ () => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
1745
+ new HostInputInvalid()
1746
+ );
1747
+ if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
1748
+ const session = yield* sqlSession(replay);
1749
+ const execute = () => Effect_exports.gen(function* () {
1029
1750
  const output = yield* Effect_exports.gen(function* () {
1030
1751
  running = yield* captureTelemetry;
1031
- const fetch = yield* invocationFetch(invocationSignal);
1752
+ const fetch = yield* appInvocationFetch(fetching.signal);
1032
1753
  return yield* tool.run(
1033
1754
  {
1034
1755
  ...bound,
1035
1756
  fetch,
1036
1757
  workflows: kind === "mutate" ? workflowControls : workflowReads,
1037
- ...db === void 0 || native.database === void 0 ? {} : {
1038
- db: authorDatabase(
1039
- native.database.tables,
1040
- db,
1041
- invocationSignal,
1042
- kind === "mutate"
1043
- )
1044
- }
1758
+ sql: kind === "mutate" ? session.writer : session.reader,
1759
+ ...kind === "mutate" ? { events: emitter() } : {}
1045
1760
  },
1046
1761
  input
1047
1762
  );
@@ -1056,14 +1771,15 @@ function dispatch(app, request, context, signal) {
1056
1771
  const error = Cause_exports.squash(cause);
1057
1772
  const provider = parseProviderError(error);
1058
1773
  const response = Schema_exports.decodeUnknownOption(OpenapiResponseError)(error);
1774
+ const mcp = parseMcpError(error, secrets);
1059
1775
  const failure = Schema_exports.decodeUnknownOption(ElicitationFailed)(error);
1060
1776
  return Effect_exports.fail(
1061
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(response) ? new OpenapiResponseError({
1777
+ Option_exports.isSome(provider) ? leavingProviderError(provider.value, secrets, "call") : Option_exports.isSome(response) ? new OpenapiResponseError({
1062
1778
  code: response.value.code,
1063
1779
  status: response.value.status,
1064
1780
  message: response.value.message,
1065
1781
  ...response.value.recovery === void 0 ? {} : { recovery: response.value.recovery }
1066
- }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1782
+ }) : Option_exports.isSome(mcp) ? mcp.value : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1067
1783
  );
1068
1784
  }),
1069
1785
  Effect_exports.withSpan("app.operation.execute", {
@@ -1080,30 +1796,11 @@ function dispatch(app, request, context, signal) {
1080
1796
  new HostOutputInvalid()
1081
1797
  );
1082
1798
  });
1083
- const replay = context.replay === void 0 ? void 0 : yield* safe2(
1084
- () => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
1085
- new HostInputInvalid()
1086
- );
1087
- if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
1088
- if (native.database === void 0) return yield* withinDeadline(execute());
1089
- const storage = context.storage ?? unavailableStorage;
1090
- return yield* storage[kind === "query" ? "read" : "mutate"](
1091
- native.database.schema,
1092
- (db) => withinDeadline(
1093
- replay === void 0 ? execute(db) : db.once(replay.key, replay.fingerprint, () => execute(db))
1094
- )
1095
- ).pipe(
1096
- Effect_exports.catchTags({
1097
- AppDatabaseError: storageFailure,
1098
- DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
1099
- AppStorageUnavailable: storageFailure,
1100
- AppStorageError: storageFailure
1101
- })
1102
- );
1799
+ return yield* withinDeadline(execute());
1103
1800
  })
1104
1801
  );
1105
1802
  }
1106
- function checkAccount(slots, declared, requirement, context, signal) {
1803
+ function checkAccount(slots, declared, requirement, context, signal, deadline) {
1107
1804
  return Effect_exports.gen(function* () {
1108
1805
  const selection = Object.hasOwn(slots, requirement) ? slots[requirement] : void 0;
1109
1806
  const slot = Object.hasOwn(declared.accounts, requirement) ? declared.accounts[requirement] : void 0;
@@ -1120,7 +1817,12 @@ function checkAccount(slots, declared, requirement, context, signal) {
1120
1817
  if (account === void 0 || !("id" in account)) return yield* new HostAccountsInvalid();
1121
1818
  const result = yield* Effect_exports.suspend(
1122
1819
  () => Effect_exports.gen(function* () {
1123
- return yield* health.run({ account, fetch: yield* invocationFetch(signal), signal });
1820
+ return yield* health.run({
1821
+ account,
1822
+ fetch: yield* appInvocationFetch(signal),
1823
+ signal,
1824
+ ...deadline === void 0 ? {} : { deadline }
1825
+ });
1124
1826
  })
1125
1827
  ).pipe(
1126
1828
  Effect_exports.catchCause((cause) => {
@@ -1128,8 +1830,9 @@ function checkAccount(slots, declared, requirement, context, signal) {
1128
1830
  const error = Cause_exports.squash(cause);
1129
1831
  const status = Schema_exports.decodeUnknownOption(ResponseStatusError)(error);
1130
1832
  const classified = Option_exports.isSome(status) ? Option_exports.fromNullishOr(httpProviderError(status.value.status)) : parseProviderError(error);
1833
+ const secrets = accountSecrets(context.accounts);
1131
1834
  return Effect_exports.fail(
1132
- Option_exports.isSome(classified) ? accountProviderError(classified.value, account.id) : new HostOperationFailed()
1835
+ Option_exports.isSome(classified) ? leavingProviderError(accountProviderError(classified.value, account.id), secrets) : new HostOperationFailed(failureDetail(error, secrets))
1133
1836
  );
1134
1837
  }),
1135
1838
  Effect_exports.withSpan("app.account.check")
@@ -1143,20 +1846,6 @@ function checkAccount(slots, declared, requirement, context, signal) {
1143
1846
  );
1144
1847
  });
1145
1848
  }
1146
- var parseSkillLoadFailed = (error) => Schema_exports.decodeUnknownOption(SkillLoadFailed)(error).pipe(
1147
- Option_exports.map(
1148
- ({ reason, message, status }) => new SkillLoadFailed({
1149
- reason,
1150
- ...message ? { message } : {},
1151
- ...status === void 0 ? {} : { status }
1152
- })
1153
- )
1154
- );
1155
- var parseMcpError = (error) => Schema_exports.decodeUnknownOption(McpError)(error).pipe(
1156
- Option_exports.map(
1157
- ({ phase, reason, status }) => new McpError({ phase, reason, ...status === void 0 ? {} : { status } })
1158
- )
1159
- );
1160
1849
  var errorStatus = Match_exports.type().pipe(
1161
1850
  Match_exports.tagsExhaustive({
1162
1851
  ProviderError: () => 502,
@@ -1196,20 +1885,37 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1196
1885
  ...command.operation === "call" ? { "executor.tool.name": command.tool } : {}
1197
1886
  });
1198
1887
  let toolError = false;
1199
- const value = yield* dispatch(app, command, context, request.signal).pipe(
1888
+ const emitted = [];
1889
+ const value = yield* dispatch(app, command, context, request.signal, emitted).pipe(
1200
1890
  Effect_exports.provideService(ToolResultObservation, {
1201
1891
  failed: () => {
1202
1892
  toolError = true;
1203
1893
  }
1204
1894
  }),
1205
- Effect_exports.withSpan(`app.${command.operation}`)
1895
+ // Name what failed on the span; the bounded message stays in the reply only. The host
1896
+ // records an app's own error names and codes as `unrecognized` (telemetry `app-records`).
1897
+ Effect_exports.tapError(
1898
+ (error) => (error._tag === "HostEvaluationFailed" || error._tag === "HostOperationFailed" || error._tag === "HostDeclarationInvalid") && error.errorName !== void 0 ? Effect_exports.annotateCurrentSpan({
1899
+ "error.type": error.errorName,
1900
+ ...error.source === void 0 ? {} : { "executor.failure.source": error.source },
1901
+ ...error.code === void 0 ? {} : { "executor.failure.code": error.code }
1902
+ }) : Effect_exports.void
1903
+ ),
1904
+ // Tool operations time themselves, dividing their time by who owned the work in progress.
1905
+ // Other operations do not.
1906
+ command.operation === "call" || command.operation === "query" || command.operation === "mutate" ? timedInvocation(command.operation) : Effect_exports.withSpan(`app.${command.operation}`)
1206
1907
  );
1207
1908
  if (toolError)
1208
1909
  yield* Effect_exports.annotateCurrentSpan({
1209
1910
  "executor.outcome": "failed",
1210
1911
  "error.type": "McpToolError"
1211
1912
  });
1212
- return Response.json({ ok: true, value, ...toolError ? { toolError: true } : {} });
1913
+ return Response.json({
1914
+ ok: true,
1915
+ value,
1916
+ ...toolError ? { toolError: true } : {},
1917
+ ...emitted.length === 0 ? {} : { events: emitted }
1918
+ });
1213
1919
  }).pipe(
1214
1920
  Effect_exports.catch(
1215
1921
  (error) => Schema_exports.encodeEffect(HostError)(error).pipe(
@@ -1220,18 +1926,21 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1220
1926
  )
1221
1927
  ),
1222
1928
  Effect_exports.catchCause(
1223
- (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.logError(cause).pipe(
1224
- Effect_exports.andThen(
1225
- Schema_exports.encodeEffect(HostError)(
1226
- declarationInvalid(
1227
- "The app failed while it was loaded",
1228
- Cause_exports.squash(cause),
1229
- accountSecrets(context.accounts)
1929
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : (
1930
+ // The cause can carry any text the app threw; its caller receives that, not the log.
1931
+ Effect_exports.logError("The app's request failed unexpectedly").pipe(
1932
+ Effect_exports.andThen(
1933
+ Schema_exports.encodeEffect(HostError)(
1934
+ declarationInvalid(
1935
+ "The app failed while it was loaded",
1936
+ Cause_exports.squash(cause),
1937
+ accountSecrets(context.accounts)
1938
+ )
1230
1939
  )
1231
- )
1232
- ),
1233
- Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1234
- Effect_exports.orDie
1940
+ ),
1941
+ Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1942
+ Effect_exports.orDie
1943
+ )
1235
1944
  )
1236
1945
  )
1237
1946
  );