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