apps 0.0.1-beta.8 → 0.0.1-beta.80

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 (180) hide show
  1. package/README.md +25 -22
  2. package/framework-reference.json +1 -1
  3. package/js/chunk-4IN2N5CY.js +348 -0
  4. package/js/chunk-5FHWNLCI.js +88 -0
  5. package/js/{chunk-M3B3DE4K.js → chunk-74YVXBKY.js} +463 -218
  6. package/js/chunk-BIUWK47W.js +49 -0
  7. package/js/{chunk-RJDDBDSN.js → chunk-C6P3YMHI.js} +789 -171
  8. package/js/chunk-CDXQDN7W.js +92 -0
  9. package/js/{chunk-UESPOTUI.js → chunk-CT3QZBWU.js} +861 -231
  10. package/js/{chunk-UK573G7W.js → chunk-EOPQ727L.js} +87 -51
  11. package/js/{chunk-RFVIONFX.js → chunk-EZCV4Q4R.js} +123 -44
  12. package/js/{chunk-27F7W2LG.js → chunk-H2CJWXA3.js} +2 -2
  13. package/js/{chunk-JU7VHODU.js → chunk-H72MEDMN.js} +65 -10
  14. package/js/{chunk-CDL5PM2Q.js → chunk-IFJU5SYQ.js} +19082 -18402
  15. package/js/{chunk-72JNVHPK.js → chunk-IUPDGBBF.js} +4 -3
  16. package/js/{chunk-VFZKSM3T.js → chunk-JPEUKEV4.js} +3 -3
  17. package/js/{chunk-5T57N25Q.js → chunk-KGCTYL2S.js} +511 -63
  18. package/js/{chunk-KUMBKVJD.js → chunk-KLYSEHUD.js} +2 -2
  19. package/js/{chunk-WLE7WX2U.js → chunk-NG56RPCA.js} +2348 -472
  20. package/js/chunk-OD3KFKZD.js +1617 -0
  21. package/js/chunk-OK4MIBPW.js +334 -0
  22. package/js/{chunk-57RKNWL2.js → chunk-PD6I2SDG.js} +4 -4
  23. package/js/chunk-PW4S2HP5.js +426 -0
  24. package/js/chunk-Q4IZAUIF.js +285 -0
  25. package/js/{chunk-FL2QR3XW.js → chunk-Q5S3SWMO.js} +333 -69
  26. package/js/{chunk-Z5M2LQOZ.js → chunk-SNKDWIYL.js} +67 -55
  27. package/js/{chunk-IJX4CYZO.js → chunk-TUMGL2OC.js} +228 -264
  28. package/js/{chunk-CMYUWAX7.js → chunk-WFCOT6UW.js} +126 -31
  29. package/js/{chunk-IPI4MFSN.js → chunk-XBG7HHXC.js} +2 -2
  30. package/js/chunk-ZYXY6JLH.js +171 -0
  31. package/js/client.js +142 -94
  32. package/js/contracts.js +127 -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 +4071 -1357
  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 +8604 -223
  50. package/package.json +3 -4
  51. package/runtime.json +1 -1
  52. package/types/app-cache/src/contracts/cache.d.ts +18 -0
  53. package/types/app-cache/src/index.d.ts +34 -2
  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 +23 -7
  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 +649 -17
  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 +3843 -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 +37 -3
  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 +28 -1
  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 +18 -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 +28 -9
  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/apps/src/ui-serving.d.ts +1 -1
  147. package/types/telemetry/src/app-records.d.ts +42 -0
  148. package/types/telemetry/src/browser-operations.d.ts +2 -2
  149. package/types/telemetry/src/browser.d.ts +8 -3
  150. package/types/telemetry/src/config.d.ts +2 -2
  151. package/types/telemetry/src/index.d.ts +2 -1
  152. package/types/telemetry/src/layer.d.ts +2 -2
  153. package/types/telemetry/src/measurements.d.ts +1 -1
  154. package/types/telemetry/src/ownership.d.ts +60 -0
  155. package/types/telemetry/src/recorded-failure.d.ts +29 -0
  156. package/types/telemetry/src/relay.d.ts +16 -6
  157. package/types/telemetry/src/span-attributes.d.ts +17 -1
  158. package/types/telemetry/src/transport.d.ts +8 -1
  159. package/types/utils/src/api-error.d.ts +55 -0
  160. package/types/utils/src/connection-failure.d.ts +33 -0
  161. package/types/utils/src/recorded-message.d.ts +18 -0
  162. package/types/utils/src/user-facing-error.d.ts +83 -0
  163. package/js/chunk-MKWZPDR6.js +0 -63
  164. package/js/chunk-N7YDVXYJ.js +0 -186
  165. package/js/chunk-NKLWZJLE.js +0 -172
  166. package/js/chunk-OCYUEU47.js +0 -224
  167. package/js/chunk-PJJ24GU7.js +0 -877
  168. package/js/chunk-PZB6T6KU.js +0 -19
  169. package/js/chunk-R3EV5FTO.js +0 -97
  170. package/js/chunk-YXQHV65J.js +0 -242
  171. package/js/chunk-ZQINWV4W.js +0 -630
  172. package/types/app-data/src/implementation/cursor.d.ts +0 -10
  173. package/types/app-data/src/implementation/index-key.d.ts +0 -7
  174. package/types/app-data/src/implementation/promise.d.ts +0 -68
  175. package/types/app-data/src/implementation/range.d.ts +0 -8
  176. package/types/app-data/src/implementation/schema.d.ts +0 -18
  177. package/types/app-data/src/implementation/sqlite.d.ts +0 -11
  178. package/types/app-data/src/index.d.ts +0 -4
  179. package/types/apps/src/contracts/storage.d.ts +0 -68
  180. package/types/apps/src/implementation/storage.d.ts +0 -15
@@ -1,39 +1,45 @@
1
1
  import {
2
- makeCache
3
- } from "./chunk-NKLWZJLE.js";
2
+ authorCache,
3
+ unavailableCache
4
+ } from "./chunk-OK4MIBPW.js";
4
5
  import {
5
6
  accountSecrets,
6
7
  boundFailureMessage,
7
8
  describeFailure,
8
9
  failureDetail,
10
+ leavingProviderError,
11
+ parseMcpError,
12
+ parseSkillLoadFailed,
9
13
  readCatalog,
10
14
  routerSkills
11
- } from "./chunk-FL2QR3XW.js";
15
+ } from "./chunk-Q5S3SWMO.js";
16
+ import {
17
+ appInvocationFetch
18
+ } from "./chunk-BIUWK47W.js";
12
19
  import {
13
20
  folderSkillsEffect
14
- } from "./chunk-IPI4MFSN.js";
21
+ } from "./chunk-XBG7HHXC.js";
15
22
  import {
16
23
  ResponseStatusError,
17
- authorDatabase,
24
+ declaredEvents,
18
25
  isApp,
26
+ makeEmitter,
19
27
  toEffectApp,
20
- unavailableStorage
21
- } from "./chunk-YXQHV65J.js";
22
- import {
23
- parseDatabaseSchema
24
- } from "./chunk-ZQINWV4W.js";
28
+ withPlacements
29
+ } from "./chunk-PW4S2HP5.js";
25
30
  import {
26
31
  declaredOperations,
27
- fromPromise,
28
32
  locate,
29
- nativeOperation,
30
- toPromise
31
- } from "./chunk-Z5M2LQOZ.js";
33
+ nativeOperation
34
+ } from "./chunk-SNKDWIYL.js";
32
35
  import {
33
36
  accountProviderError,
37
+ appCode,
38
+ fromPromise,
34
39
  httpProviderError,
35
- parseProviderError
36
- } from "./chunk-MKWZPDR6.js";
40
+ parseProviderError,
41
+ toPromise
42
+ } from "./chunk-ZYXY6JLH.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";
85
- import {
86
- CacheError
87
- } from "./chunk-R3EV5FTO.js";
94
+ } from "./chunk-NG56RPCA.js";
88
95
  import {
89
96
  AppSkills,
90
- SkillFile,
91
- SkillLoadFailed
92
- } from "./chunk-JU7VHODU.js";
97
+ SkillFile
98
+ } from "./chunk-H72MEDMN.js";
93
99
  import {
94
- captureTelemetry,
95
- invocationFetch
96
- } from "./chunk-RJDDBDSN.js";
97
- import {
98
- decoderOf,
100
+ allowedValues,
101
+ echoableKey,
99
102
  importedJsonSchema,
103
+ importedSchemaKeys,
100
104
  jsonSchemaDecoder,
101
- jsonSchemaDocument
102
- } from "./chunk-5T57N25Q.js";
105
+ jsonSchemaDocument,
106
+ maxAlternativeKeys,
107
+ missingKey,
108
+ missingKeyText,
109
+ objectShape,
110
+ unionShape
111
+ } from "./chunk-KGCTYL2S.js";
112
+ import {
113
+ captureTelemetry,
114
+ makeOwnershipAccounting,
115
+ measuredSpan,
116
+ owned
117
+ } from "./chunk-C6P3YMHI.js";
103
118
  import {
104
119
  JsonObject,
105
120
  JsonValue
106
- } from "./chunk-27F7W2LG.js";
121
+ } from "./chunk-H2CJWXA3.js";
107
122
  import {
123
+ Base64_exports,
108
124
  Cause_exports,
109
125
  Clock_exports,
110
126
  Effect_exports,
111
- Encoding_exports,
112
127
  Match_exports,
113
128
  Option_exports,
114
129
  Redacted_exports,
130
+ SchemaAST_exports,
115
131
  SchemaIssue_exports,
116
132
  Schema_exports,
117
133
  Stream_exports
118
- } from "./chunk-CDL5PM2Q.js";
134
+ } from "./chunk-IFJU5SYQ.js";
135
+
136
+ // src/implementation/invocation-timing.ts
137
+ var elicitationWaitSpan = "app.elicitation.wait";
138
+ var workflowControlSpan = "app.workflow.control";
139
+ var timedInvocation = (operation) => (effect) => Effect_exports.gen(function* () {
140
+ const report = yield* InvocationTimingSink;
141
+ return yield* effect.pipe(
142
+ measuredSpan(`app.${operation}`, {}, (start) => {
143
+ const accounting = makeOwnershipAccounting(start, "executor");
144
+ return {
145
+ around: accounting.observe,
146
+ end: (end, span) => {
147
+ const spent = accounting.read(end);
148
+ report({
149
+ elapsedMs: Number(end - start) / 1e6,
150
+ upstreamMs: spent.upstream,
151
+ elicitationMs: spent.person,
152
+ authoredMs: spent.app,
153
+ leaseMs: spent.lease,
154
+ backgroundMs: spent.background
155
+ });
156
+ span.attribute("executor.upstream.wait_ms", spent.upstream);
157
+ span.attribute("executor.elicitation.wait_ms", spent.person);
158
+ span.attribute("executor.authored_ms", spent.app);
159
+ span.attribute("executor.lease.wait_ms", spent.lease);
160
+ span.attribute("executor.background_ms", spent.background);
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,79 +662,414 @@ 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
 
492
- // src/implementation/cache.ts
493
- var unavailableCache = {
494
- transport: () => Effect_exports.fail(new CacheError({ reason: "unavailable" })),
495
- background: () => Effect_exports.die(new Error("Cache background runner is unavailable"))
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
+ };
496
690
  };
497
- var authorCache = (host, accounts, signal, deadline) => {
498
- const scoped = (scope, callerSignal = signal) => {
499
- const cache = makeCache(host.transport, host.background, scope, deadline);
500
- const load = (method, options) => cache[method]({
501
- key: options.key,
502
- schema: decoderOf(options.schema),
503
- freshFor: options.freshFor,
504
- ...options.staleFor === void 0 ? {} : { staleFor: options.staleFor },
505
- load: Effect_exports.acquireUseRelease(
506
- Effect_exports.sync(() => new AbortController()),
507
- (controller) => invocationFetch(controller.signal).pipe(
508
- Effect_exports.flatMap(
509
- (fetch) => fromPromise(options.load)({
510
- fetch,
511
- signal: controller.signal,
512
- cache: scoped(scope, controller.signal)
513
- })
514
- )
515
- ),
516
- (controller) => Effect_exports.sync(() => controller.abort())
517
- )
518
- });
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
+ };
519
808
  return {
520
- get: toPromise((options) => load("get", options), callerSignal),
521
- revalidate: toPromise(
522
- (options) => load("revalidate", options),
523
- callerSignal
524
- ),
525
- read: toPromise(
526
- (key, schema) => cache.read([key]).pipe(
527
- Effect_exports.flatMap((entries) => {
528
- const entry = entries[0];
529
- return entry === void 0 || entry === null ? Effect_exports.succeed(void 0) : Schema_exports.decodeUnknownEffect(decoderOf(schema))(entry.value);
530
- })
531
- ),
532
- callerSignal
533
- ),
534
- readMany: toPromise(
535
- (keys, schema) => cache.read(keys).pipe(
536
- Effect_exports.flatMap(
537
- (entries) => Effect_exports.forEach(
538
- entries,
539
- (entry) => entry === null ? Effect_exports.succeed(void 0) : Schema_exports.decodeUnknownEffect(decoderOf(schema))(entry.value)
540
- )
541
- )
542
- ),
543
- callerSignal
544
- ),
545
- write: toPromise(cache.write, callerSignal),
546
- invalidate: toPromise(cache.invalidate, callerSignal),
547
- forAccount: (account) => {
548
- const bound = Object.values(accounts).flatMap((value) => Array.isArray(value) ? value : [value]).find((value) => value.id === account.id);
549
- if (bound === void 0) throw new CacheError({ reason: "invalid" });
550
- return scoped(
551
- { account: bound.id, method: bound.method, generation: bound.generation },
552
- callerSignal
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
553
872
  );
873
+ return JSON.parse(encoded);
874
+ } finally {
875
+ open = false;
876
+ handle.end();
554
877
  }
555
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
+ }
556
897
  };
557
- return scoped("shared");
558
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
+ });
559
1073
 
560
1074
  // src/implementation/host.ts
561
1075
  var WireCatalog = Schema_exports.Struct({
@@ -575,9 +1089,9 @@ var evaluationSafe = (work, secrets) => work.pipe(
575
1089
  const error = Cause_exports.squash(cause);
576
1090
  const provider = parseProviderError(error);
577
1091
  const skills = parseSkillLoadFailed(error);
578
- const mcp = parseMcpError(error);
1092
+ const mcp = parseMcpError(error, secrets);
579
1093
  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))
1094
+ 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
1095
  );
582
1096
  })
583
1097
  );
@@ -594,6 +1108,15 @@ var declarationSafe = (work, summary) => Effect_exports.suspend(work).pipe(
594
1108
  (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(declarationInvalid(summary, Cause_exports.squash(cause)))
595
1109
  )
596
1110
  );
1111
+ function declaredExposure(exposure) {
1112
+ const named = (kind) => Object.entries(exposure ?? {}).filter(([, value]) => value === kind).map(([field]) => field).sort();
1113
+ const plain = named("plain");
1114
+ const raw = named("raw");
1115
+ return { ...plain.length === 0 ? {} : { plain }, ...raw.length === 0 ? {} : { raw } };
1116
+ }
1117
+ function declaredPlacements(request) {
1118
+ return request === void 0 || request.length === 0 ? {} : { request: normalizePlacements(request) };
1119
+ }
597
1120
  function providerDeclaration(provider) {
598
1121
  return declarationSafe(
599
1122
  () => Effect_exports.gen(function* () {
@@ -604,27 +1127,33 @@ function providerDeclaration(provider) {
604
1127
  auth.set(name, {
605
1128
  type: "secrets",
606
1129
  label: method.label,
607
- fields: yield* jsonSchemaDocument(method.fields)
1130
+ fields: yield* jsonSchemaDocument(method.fields),
1131
+ ...declaredExposure(method.exposure),
1132
+ ...declaredPlacements(method.request)
608
1133
  });
609
1134
  break;
610
1135
  case "oauth2":
611
1136
  auth.set(name, {
612
1137
  type: "oauth2",
613
1138
  ...method.config,
614
- response: yield* jsonSchemaDocument(method.response)
1139
+ response: yield* jsonSchemaDocument(method.response),
1140
+ ...declaredExposure(method.exposure),
1141
+ ...declaredPlacements(method.request)
615
1142
  });
616
1143
  break;
617
1144
  }
618
1145
  }
619
1146
  return yield* Schema_exports.decodeUnknownEffect(DeclaredProvider)({
620
1147
  name: provider.name,
621
- auth: Object.fromEntries(auth)
1148
+ auth: Object.fromEntries(auth),
1149
+ // Order and repetition carry no meaning, so neither changes the provider's identity.
1150
+ ...provider.hosts === void 0 ? {} : { hosts: [...new Set(provider.hosts)].sort() }
622
1151
  });
623
1152
  }),
624
1153
  `Account provider "${provider.name}" has an invalid declaration`
625
1154
  );
626
1155
  }
627
- function requirements(slots, database) {
1156
+ function requirements(slots, sql, events) {
628
1157
  return Effect_exports.gen(function* () {
629
1158
  const accounts = /* @__PURE__ */ new Map();
630
1159
  for (const [slot, selection] of Object.entries(slots)) {
@@ -638,10 +1167,16 @@ function requirements(slots, database) {
638
1167
  return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
639
1168
  accounts: Object.fromEntries(accounts),
640
1169
  capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
641
- ...database === void 0 ? {} : { database }
1170
+ ...sql ? { sql: true } : {},
1171
+ ...events === void 0 || Object.keys(events).length === 0 ? {} : {
1172
+ events: yield* declarationSafe(
1173
+ () => declaredEvents(events),
1174
+ "The app's event declarations are invalid"
1175
+ )
1176
+ }
642
1177
  }).pipe(
643
1178
  Effect_exports.mapError(
644
- (cause) => declarationInvalid("The app's account or database declarations are invalid", cause)
1179
+ (cause) => declarationInvalid("The app's account declarations are invalid", cause)
645
1180
  )
646
1181
  );
647
1182
  });
@@ -653,6 +1188,17 @@ function canonical(value) {
653
1188
  }
654
1189
  return JSON.stringify(value);
655
1190
  }
1191
+ function withoutGrants({ hosts: _hosts, ...provider }) {
1192
+ return {
1193
+ ...provider,
1194
+ auth: Object.fromEntries(
1195
+ Object.entries(provider.auth).map(([name, { request: _request, ...method }]) => [
1196
+ name,
1197
+ method
1198
+ ])
1199
+ )
1200
+ };
1201
+ }
656
1202
  function bindAccounts(slots, declarations, context) {
657
1203
  return safe2(
658
1204
  () => Effect_exports.gen(function* () {
@@ -678,14 +1224,17 @@ function bindAccounts(slots, declarations, context) {
678
1224
  for (const account of accounts) {
679
1225
  if (ids.has(account.id)) return yield* Effect_exports.fail(new HostAccountsInvalid());
680
1226
  ids.add(account.id);
681
- if (canonical(account.provider) !== canonical(requirement.definition) || !Object.hasOwn(provider.auth, account.method))
1227
+ if (canonical(withoutGrants(account.provider)) !== canonical(withoutGrants(requirement.definition)) || !Object.hasOwn(provider.auth, account.method))
682
1228
  return yield* Effect_exports.fail(new HostAccountsInvalid());
683
1229
  const method = provider.auth[account.method];
684
1230
  if (method === void 0) return yield* Effect_exports.fail(new HostAccountsInvalid());
685
1231
  const fields = yield* Schema_exports.decodeUnknownEffect(
686
1232
  method._tag === "secrets" ? method.fields : method.response
687
1233
  )(account.fields);
688
- values.push({ id: account.id, method: account.method, fields });
1234
+ const granted = Object.hasOwn(account.provider.auth, account.method) ? account.provider.auth[account.method]?.request : void 0;
1235
+ values.push(
1236
+ withPlacements({ id: account.id, method: account.method, fields }, granted)
1237
+ );
689
1238
  }
690
1239
  if (many) bound.set(slot, values);
691
1240
  else {
@@ -699,7 +1248,42 @@ function bindAccounts(slots, declarations, context) {
699
1248
  new HostAccountsInvalid()
700
1249
  );
701
1250
  }
702
- function dispatch(app, request, context, signal) {
1251
+ var fetchLifetime = (signal, background) => Effect_exports.acquireRelease(
1252
+ Effect_exports.sync(() => {
1253
+ const controller = new AbortController();
1254
+ let refreshes = 0;
1255
+ let ended = false;
1256
+ const settle = () => {
1257
+ if (ended && refreshes === 0) controller.abort();
1258
+ };
1259
+ const end = () => {
1260
+ ended = true;
1261
+ settle();
1262
+ };
1263
+ signal.addEventListener("abort", end, { once: true });
1264
+ if (signal.aborted) end();
1265
+ const settled = Effect_exports.sync(() => {
1266
+ refreshes -= 1;
1267
+ settle();
1268
+ });
1269
+ return {
1270
+ signal: controller.signal,
1271
+ close: () => {
1272
+ signal.removeEventListener("abort", end);
1273
+ end();
1274
+ },
1275
+ /** Counted from the hand-off, so a refresh that has not started yet keeps the fetch. */
1276
+ background: (task) => Effect_exports.suspend(() => {
1277
+ refreshes += 1;
1278
+ return background(task.pipe(Effect_exports.ensuring(settled))).pipe(
1279
+ Effect_exports.onError(() => settled)
1280
+ );
1281
+ })
1282
+ };
1283
+ }),
1284
+ (lifetime) => Effect_exports.sync(lifetime.close)
1285
+ );
1286
+ function dispatch(app, request, context, signal, emitted) {
703
1287
  return Effect_exports.scoped(
704
1288
  Effect_exports.gen(function* () {
705
1289
  if (!isApp(app))
@@ -708,28 +1292,52 @@ function dispatch(app, request, context, signal) {
708
1292
  );
709
1293
  const native = toEffectApp(app);
710
1294
  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
- );
1295
+ const ownsSql = hasMigrations(context.files ?? []);
1296
+ const declared = yield* requirements(native.accounts, ownsSql, native.events);
1297
+ if (request.operation === "requirements")
723
1298
  return yield* safe2(
724
1299
  () => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
725
1300
  new HostDeclarationInvalid()
726
1301
  );
1302
+ if (request.operation === "migrate") {
1303
+ if (!ownsSql) return yield* new HostOperationNotFound();
1304
+ const storage2 = context.storage;
1305
+ if (storage2 === void 0)
1306
+ return yield* new HostOperationFailed(
1307
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1308
+ );
1309
+ const sources = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(SkillFile))(
1310
+ context.files ?? []
1311
+ ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
1312
+ const applied = yield* migrate(storage2, sources).pipe(
1313
+ Effect_exports.mapError((error) => new HostOperationFailed(failureDetail(error, secrets))),
1314
+ Effect_exports.withSpan("app.sql.migrate")
1315
+ );
1316
+ return yield* safe2(
1317
+ () => Schema_exports.decodeUnknownEffect(JsonValue)(applied),
1318
+ new HostOutputInvalid()
1319
+ );
727
1320
  }
728
1321
  const lifetime = yield* Effect_exports.acquireRelease(
729
1322
  Effect_exports.sync(() => new AbortController()),
730
1323
  (controller) => Effect_exports.sync(() => controller.abort())
731
1324
  );
732
1325
  const invocationSignal = AbortSignal.any([signal, lifetime.signal]);
1326
+ const storage = context.storage;
1327
+ const sqlSession = (step) => !ownsSql ? Effect_exports.succeed({ reader: noDatabase, writer: noDatabase }) : storage === void 0 ? Effect_exports.fail(
1328
+ new HostOperationFailed(
1329
+ failureDetail(new Error("This host gave the app no SQL storage."), secrets)
1330
+ )
1331
+ ) : Effect_exports.acquireRelease(
1332
+ Effect_exports.sync(
1333
+ () => authorSql(storage, {
1334
+ signal: invocationSignal,
1335
+ emitted,
1336
+ ...step === void 0 ? {} : { step }
1337
+ })
1338
+ ),
1339
+ (session2) => Effect_exports.sync(session2.close)
1340
+ );
733
1341
  const deadline = context.deadline === void 0 ? void 0 : yield* safe2(
734
1342
  () => Schema_exports.decodeUnknownEffect(InvocationDeadline)(context.deadline),
735
1343
  new HostInputInvalid()
@@ -756,33 +1364,56 @@ function dispatch(app, request, context, signal) {
756
1364
  declared,
757
1365
  request.requirement,
758
1366
  context,
759
- invocationSignal
1367
+ invocationSignal,
1368
+ deadline
760
1369
  ).pipe(withinDeadline);
761
1370
  let running;
762
- let transactionOpen = false;
763
1371
  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"),
1372
+ () => running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
1373
+ // Delivering the question and waiting for its answer is the person's time.
1374
+ owned("person", "app.tool.elicitation"),
766
1375
  Effect_exports.provideContext(running.context)
767
1376
  ) : Effect_exports.fail(new ElicitationFailed({ reason: "unavailable" }))
768
1377
  );
769
1378
  const unavailableWorkflow = () => Effect_exports.fail(new WorkflowFailure({ reason: "unavailable", retryable: false }));
1379
+ const telemetry = yield* captureTelemetry;
1380
+ const control = (operation, work) => work.pipe(
1381
+ owned("executor", workflowControlSpan, {
1382
+ attributes: { "executor.workflow.operation": operation }
1383
+ })
1384
+ );
770
1385
  const workflowControls = {
771
1386
  start: toPromise(
772
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.start(input2),
773
- invocationSignal
1387
+ (input2) => control(
1388
+ "start",
1389
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.start(input2)
1390
+ ),
1391
+ invocationSignal,
1392
+ telemetry.context
774
1393
  ),
775
1394
  get: toPromise(
776
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.get(input2),
777
- invocationSignal
1395
+ (input2) => control(
1396
+ "get",
1397
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.get(input2)
1398
+ ),
1399
+ invocationSignal,
1400
+ telemetry.context
778
1401
  ),
779
1402
  list: toPromise(
780
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.list(input2),
781
- invocationSignal
1403
+ (input2) => control(
1404
+ "list",
1405
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.list(input2)
1406
+ ),
1407
+ invocationSignal,
1408
+ telemetry.context
782
1409
  ),
783
1410
  terminate: toPromise(
784
- (input2) => context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.terminate(input2),
785
- invocationSignal
1411
+ (input2) => control(
1412
+ "terminate",
1413
+ context.workflowControls === void 0 ? unavailableWorkflow() : context.workflowControls.terminate(input2)
1414
+ ),
1415
+ invocationSignal,
1416
+ telemetry.context
786
1417
  )
787
1418
  };
788
1419
  const workflowReads = {
@@ -794,6 +1425,7 @@ function dispatch(app, request, context, signal) {
794
1425
  ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
795
1426
  let cacheCommands = 0;
796
1427
  const hostCache = context.cache ?? unavailableCache;
1428
+ const fetching = yield* fetchLifetime(signal, hostCache.background);
797
1429
  const bound = {
798
1430
  cache: authorCache(
799
1431
  {
@@ -801,10 +1433,12 @@ function dispatch(app, request, context, signal) {
801
1433
  transport: (command) => {
802
1434
  cacheCommands += 1;
803
1435
  return hostCache.transport(command);
804
- }
1436
+ },
1437
+ background: fetching.background
805
1438
  },
806
1439
  Redacted_exports.value(context.accounts),
807
1440
  invocationSignal,
1441
+ telemetry.context,
808
1442
  deadline
809
1443
  ),
810
1444
  files,
@@ -813,9 +1447,20 @@ function dispatch(app, request, context, signal) {
813
1447
  ),
814
1448
  workflows: workflowReads,
815
1449
  signal: invocationSignal,
816
- fetch: yield* invocationFetch(invocationSignal),
817
- elicit: makeElicit(delivery, invocationSignal)
1450
+ fetch: yield* appInvocationFetch(fetching.signal),
1451
+ elicit: makeElicit(delivery, invocationSignal, telemetry.context)
818
1452
  };
1453
+ const accountIds = Object.values(bound.accounts).flatMap(
1454
+ (selected) => (Array.isArray(selected) ? selected : [selected]).map(
1455
+ (account) => account.id
1456
+ )
1457
+ );
1458
+ const emitter = (sourceAccount) => makeEmitter({
1459
+ events: native.events ?? {},
1460
+ accounts: accountIds,
1461
+ ...sourceAccount === void 0 ? {} : { sourceAccount },
1462
+ emitted
1463
+ });
819
1464
  const definition = yield* evaluationSafe(native.evaluate(bound), secrets).pipe(
820
1465
  Effect_exports.withSpan("app.evaluate")
821
1466
  );
@@ -887,10 +1532,11 @@ function dispatch(app, request, context, signal) {
887
1532
  cache: authorCache(
888
1533
  context.cache ?? unavailableCache,
889
1534
  Redacted_exports.value(current.accounts),
890
- signal2
1535
+ signal2,
1536
+ (yield* captureTelemetry).context
891
1537
  ),
892
1538
  files,
893
- fetch: yield* invocationFetch(signal2),
1539
+ fetch: yield* appInvocationFetch(signal2),
894
1540
  signal: signal2,
895
1541
  runId: execution.runId,
896
1542
  stepId,
@@ -938,7 +1584,8 @@ function dispatch(app, request, context, signal) {
938
1584
  );
939
1585
  }
940
1586
  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(
1587
+ const session2 = yield* sqlSession();
1588
+ return yield* dispatchWebhook(
942
1589
  definition,
943
1590
  request,
944
1591
  {
@@ -948,27 +1595,17 @@ function dispatch(app, request, context, signal) {
948
1595
  workflows: workflowControls,
949
1596
  signal: bound.signal,
950
1597
  fetch: bound.fetch,
951
- ...db === void 0 || native.database === void 0 ? {} : {
952
- db: authorDatabase(native.database.tables, db, invocationSignal, true)
953
- }
1598
+ sql: session2.writer,
1599
+ events: emitter("sourceAccount" in request ? request.sourceAccount : void 0)
954
1600
  },
955
1601
  Redacted_exports.value(context.accounts)
956
1602
  );
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
1603
  }
969
1604
  const toolName = request.operation === "call" ? request.tool : request.name;
970
1605
  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);
1606
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets).pipe(
1607
+ Effect_exports.withSpan("app.tool.resolve")
1608
+ );
972
1609
  if (tool === void 0)
973
1610
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
974
1611
  const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
@@ -979,7 +1616,7 @@ function dispatch(app, request, context, signal) {
979
1616
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
980
1617
  ).pipe(
981
1618
  Effect_exports.catchCause(
982
- (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(inputInvalid(Cause_exports.squash(cause)))
1619
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(inputInvalid(Cause_exports.squash(cause), request.input))
983
1620
  )
984
1621
  );
985
1622
  if (context.approval !== void 0) {
@@ -1024,24 +1661,23 @@ function dispatch(app, request, context, signal) {
1024
1661
  Match_exports.exhaustive
1025
1662
  );
1026
1663
  }
1027
- const execute = (db) => Effect_exports.gen(function* () {
1028
- transactionOpen = db !== void 0;
1664
+ const replay = context.replay === void 0 ? void 0 : yield* safe2(
1665
+ () => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
1666
+ new HostInputInvalid()
1667
+ );
1668
+ if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
1669
+ const session = yield* sqlSession(replay);
1670
+ const execute = () => Effect_exports.gen(function* () {
1029
1671
  const output = yield* Effect_exports.gen(function* () {
1030
1672
  running = yield* captureTelemetry;
1031
- const fetch = yield* invocationFetch(invocationSignal);
1673
+ const fetch = yield* appInvocationFetch(fetching.signal);
1032
1674
  return yield* tool.run(
1033
1675
  {
1034
1676
  ...bound,
1035
1677
  fetch,
1036
1678
  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
- }
1679
+ sql: kind === "mutate" ? session.writer : session.reader,
1680
+ ...kind === "mutate" ? { events: emitter() } : {}
1045
1681
  },
1046
1682
  input
1047
1683
  );
@@ -1056,14 +1692,15 @@ function dispatch(app, request, context, signal) {
1056
1692
  const error = Cause_exports.squash(cause);
1057
1693
  const provider = parseProviderError(error);
1058
1694
  const response = Schema_exports.decodeUnknownOption(OpenapiResponseError)(error);
1695
+ const mcp = parseMcpError(error, secrets);
1059
1696
  const failure = Schema_exports.decodeUnknownOption(ElicitationFailed)(error);
1060
1697
  return Effect_exports.fail(
1061
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(response) ? new OpenapiResponseError({
1698
+ Option_exports.isSome(provider) ? leavingProviderError(provider.value, secrets, "call") : Option_exports.isSome(response) ? new OpenapiResponseError({
1062
1699
  code: response.value.code,
1063
1700
  status: response.value.status,
1064
1701
  message: response.value.message,
1065
1702
  ...response.value.recovery === void 0 ? {} : { recovery: response.value.recovery }
1066
- }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1703
+ }) : Option_exports.isSome(mcp) ? mcp.value : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1067
1704
  );
1068
1705
  }),
1069
1706
  Effect_exports.withSpan("app.operation.execute", {
@@ -1080,30 +1717,11 @@ function dispatch(app, request, context, signal) {
1080
1717
  new HostOutputInvalid()
1081
1718
  );
1082
1719
  });
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
- );
1720
+ return yield* withinDeadline(execute());
1103
1721
  })
1104
1722
  );
1105
1723
  }
1106
- function checkAccount(slots, declared, requirement, context, signal) {
1724
+ function checkAccount(slots, declared, requirement, context, signal, deadline) {
1107
1725
  return Effect_exports.gen(function* () {
1108
1726
  const selection = Object.hasOwn(slots, requirement) ? slots[requirement] : void 0;
1109
1727
  const slot = Object.hasOwn(declared.accounts, requirement) ? declared.accounts[requirement] : void 0;
@@ -1120,7 +1738,12 @@ function checkAccount(slots, declared, requirement, context, signal) {
1120
1738
  if (account === void 0 || !("id" in account)) return yield* new HostAccountsInvalid();
1121
1739
  const result = yield* Effect_exports.suspend(
1122
1740
  () => Effect_exports.gen(function* () {
1123
- return yield* health.run({ account, fetch: yield* invocationFetch(signal), signal });
1741
+ return yield* health.run({
1742
+ account,
1743
+ fetch: yield* appInvocationFetch(signal),
1744
+ signal,
1745
+ ...deadline === void 0 ? {} : { deadline }
1746
+ });
1124
1747
  })
1125
1748
  ).pipe(
1126
1749
  Effect_exports.catchCause((cause) => {
@@ -1128,8 +1751,9 @@ function checkAccount(slots, declared, requirement, context, signal) {
1128
1751
  const error = Cause_exports.squash(cause);
1129
1752
  const status = Schema_exports.decodeUnknownOption(ResponseStatusError)(error);
1130
1753
  const classified = Option_exports.isSome(status) ? Option_exports.fromNullishOr(httpProviderError(status.value.status)) : parseProviderError(error);
1754
+ const secrets = accountSecrets(context.accounts);
1131
1755
  return Effect_exports.fail(
1132
- Option_exports.isSome(classified) ? accountProviderError(classified.value, account.id) : new HostOperationFailed()
1756
+ Option_exports.isSome(classified) ? leavingProviderError(accountProviderError(classified.value, account.id), secrets) : new HostOperationFailed(failureDetail(error, secrets))
1133
1757
  );
1134
1758
  }),
1135
1759
  Effect_exports.withSpan("app.account.check")
@@ -1143,20 +1767,6 @@ function checkAccount(slots, declared, requirement, context, signal) {
1143
1767
  );
1144
1768
  });
1145
1769
  }
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
1770
  var errorStatus = Match_exports.type().pipe(
1161
1771
  Match_exports.tagsExhaustive({
1162
1772
  ProviderError: () => 502,
@@ -1196,20 +1806,37 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1196
1806
  ...command.operation === "call" ? { "executor.tool.name": command.tool } : {}
1197
1807
  });
1198
1808
  let toolError = false;
1199
- const value = yield* dispatch(app, command, context, request.signal).pipe(
1809
+ const emitted = [];
1810
+ const value = yield* dispatch(app, command, context, request.signal, emitted).pipe(
1200
1811
  Effect_exports.provideService(ToolResultObservation, {
1201
1812
  failed: () => {
1202
1813
  toolError = true;
1203
1814
  }
1204
1815
  }),
1205
- Effect_exports.withSpan(`app.${command.operation}`)
1816
+ // Name what failed on the span; the bounded message stays in the reply only. The host
1817
+ // records an app's own error names and codes as `unrecognized` (telemetry `app-records`).
1818
+ Effect_exports.tapError(
1819
+ (error) => (error._tag === "HostEvaluationFailed" || error._tag === "HostOperationFailed" || error._tag === "HostDeclarationInvalid") && error.errorName !== void 0 ? Effect_exports.annotateCurrentSpan({
1820
+ "error.type": error.errorName,
1821
+ ...error.source === void 0 ? {} : { "executor.failure.source": error.source },
1822
+ ...error.code === void 0 ? {} : { "executor.failure.code": error.code }
1823
+ }) : Effect_exports.void
1824
+ ),
1825
+ // Tool operations time themselves, dividing their time by who owned the work in progress.
1826
+ // Other operations do not.
1827
+ command.operation === "call" || command.operation === "query" || command.operation === "mutate" ? timedInvocation(command.operation) : Effect_exports.withSpan(`app.${command.operation}`)
1206
1828
  );
1207
1829
  if (toolError)
1208
1830
  yield* Effect_exports.annotateCurrentSpan({
1209
1831
  "executor.outcome": "failed",
1210
1832
  "error.type": "McpToolError"
1211
1833
  });
1212
- return Response.json({ ok: true, value, ...toolError ? { toolError: true } : {} });
1834
+ return Response.json({
1835
+ ok: true,
1836
+ value,
1837
+ ...toolError ? { toolError: true } : {},
1838
+ ...emitted.length === 0 ? {} : { events: emitted }
1839
+ });
1213
1840
  }).pipe(
1214
1841
  Effect_exports.catch(
1215
1842
  (error) => Schema_exports.encodeEffect(HostError)(error).pipe(
@@ -1220,18 +1847,21 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1220
1847
  )
1221
1848
  ),
1222
1849
  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)
1850
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : (
1851
+ // The cause can carry any text the app threw; its caller receives that, not the log.
1852
+ Effect_exports.logError("The app's request failed unexpectedly").pipe(
1853
+ Effect_exports.andThen(
1854
+ Schema_exports.encodeEffect(HostError)(
1855
+ declarationInvalid(
1856
+ "The app failed while it was loaded",
1857
+ Cause_exports.squash(cause),
1858
+ accountSecrets(context.accounts)
1859
+ )
1230
1860
  )
1231
- )
1232
- ),
1233
- Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1234
- Effect_exports.orDie
1861
+ ),
1862
+ Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1863
+ Effect_exports.orDie
1864
+ )
1235
1865
  )
1236
1866
  )
1237
1867
  );