apps 0.0.1-beta.6 → 0.0.1-beta.61

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