@mayiapp/eve 0.1.0
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/LICENSE +201 -0
- package/README.md +272 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +584 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 Aaron HS
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# `@mayiapp/eve`
|
|
2
|
+
|
|
3
|
+
Durable Mayi approval channel for [Eve](https://github.com/vercel/eve) agents.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @mayiapp/eve eve
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Create the Mayi channel in the root agent:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// agent/channels/mayi.ts
|
|
15
|
+
import { mayiChannel } from "@mayiapp/eve";
|
|
16
|
+
import { credentials } from "../credentials.server";
|
|
17
|
+
|
|
18
|
+
export default mayiChannel({
|
|
19
|
+
getAccessToken: () => credentials.getAccessToken("mayi"),
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The host owns Mayi's Authorization Code + PKCE flow, securely stores and
|
|
24
|
+
refreshes the OAuth grant, and returns a current access token from
|
|
25
|
+
`getAccessToken`. The adapter and `@mayiapp/sdk` do not store tokens. Do not put an
|
|
26
|
+
access token, refresh token, static API key, or webhook endpoint ID in agent code.
|
|
27
|
+
Eden's generated integration supplies this credential binding; see the complete
|
|
28
|
+
[Eden agent template](https://github.com/asiraky/mayi/tree/main/packages/eve/examples/eden-agent).
|
|
29
|
+
|
|
30
|
+
An approval-gated tool remains ordinary Eve code:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// agent/tools/deploy-production.ts
|
|
34
|
+
import { defineTool } from "eve/tools";
|
|
35
|
+
import { always } from "eve/tools/approval";
|
|
36
|
+
import { z } from "zod";
|
|
37
|
+
|
|
38
|
+
export default defineTool({
|
|
39
|
+
description: "Deploy a version to production.",
|
|
40
|
+
inputSchema: z.object({ version: z.string() }),
|
|
41
|
+
approval: always(),
|
|
42
|
+
async execute({ version }) {
|
|
43
|
+
return deployToProduction(version);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Approval evidence
|
|
49
|
+
|
|
50
|
+
Approval happens before Eve calls the gated tool's `execute()` function. An
|
|
51
|
+
evidence hook can render from the proposed tool input, fetch an existing object,
|
|
52
|
+
or read a file created by an earlier tool. It cannot use the gated tool's result,
|
|
53
|
+
because that result does not exist until after the human approves.
|
|
54
|
+
|
|
55
|
+
Configure `artefacts` when an approval should include a PDF or image:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
export default mayiChannel({
|
|
59
|
+
getAccessToken: () => credentials.getAccessToken("mayi"),
|
|
60
|
+
async artefacts({ request, signal }) {
|
|
61
|
+
const pdf = await renderDeploymentPlan(request.action.input, { signal });
|
|
62
|
+
return [{
|
|
63
|
+
filename: "deployment-plan.pdf",
|
|
64
|
+
mediaType: "application/pdf",
|
|
65
|
+
body: pdf,
|
|
66
|
+
}];
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The hook receives the complete Eve input request, a read-only session snapshot,
|
|
72
|
+
`getSandbox()`, and an abort signal. For evidence already in object storage:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
async artefacts({ request, signal }) {
|
|
76
|
+
const response = await fetch(String(request.action.input.previewUrl), { signal });
|
|
77
|
+
return [{ filename: "preview.webp", mediaType: "image/webp", body: response.body! }];
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For a file produced by an earlier tool, read through Eve's supported sandbox
|
|
82
|
+
API and return the bytes:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
async artefacts({ getSandbox }) {
|
|
86
|
+
const sandbox = await getSandbox();
|
|
87
|
+
const body = await sandbox.readBinaryFile("/workspace/output/report.pdf");
|
|
88
|
+
return [{ filename: "report.pdf", mediaType: "application/pdf", body }];
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`undefined`, `null`, and an empty array all mean no evidence and preserve the
|
|
93
|
+
ordinary one-call approval path. A request may return at most 20 artefacts;
|
|
94
|
+
each must be a PDF, PNG, JPEG, or WebP no larger than 25 MiB. Returned order is
|
|
95
|
+
the order shown to the approver and bound into the approval manifest. Hook,
|
|
96
|
+
validation, timeout, or upload failures fail closed: Mayi does not create an
|
|
97
|
+
approval with silently missing evidence. `artefactTimeoutMs` defaults to 30
|
|
98
|
+
seconds and its signal should be passed to rendering, fetch, and file work.
|
|
99
|
+
|
|
100
|
+
## Scheduled and cross-channel handoff
|
|
101
|
+
|
|
102
|
+
Mayi handles `input.requested` only for sessions owned by the Mayi channel. It
|
|
103
|
+
does not intercept a session that belongs to Slack, Discord, the default HTTP
|
|
104
|
+
channel, or another custom channel. Start work on Mayi with Eve's
|
|
105
|
+
`receive(mayi, ...)` whenever that work may need a Mayi approval.
|
|
106
|
+
|
|
107
|
+
Task-mode schedules cannot park for human input. Use the handler form of an Eve
|
|
108
|
+
schedule and hand the run to Mayi:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// agent/schedules/check-production.ts
|
|
112
|
+
import { defineSchedule } from "eve/schedules";
|
|
113
|
+
import mayi from "../channels/mayi";
|
|
114
|
+
|
|
115
|
+
export default defineSchedule({
|
|
116
|
+
cron: "0 * * * *",
|
|
117
|
+
run({ receive, waitUntil, appAuth }) {
|
|
118
|
+
waitUntil(receive(mayi, {
|
|
119
|
+
message: "Check production and deploy if needed.",
|
|
120
|
+
target: { mayiUserId: "AbCdEfGhIjKl" },
|
|
121
|
+
auth: appAuth,
|
|
122
|
+
}));
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The same rule applies to cross-channel work. A custom channel route receives an
|
|
128
|
+
Eve `receive` helper; import the Mayi channel and hand the new session to it:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { defineChannel, POST } from "eve/channels";
|
|
132
|
+
import mayi from "./mayi";
|
|
133
|
+
|
|
134
|
+
export default defineChannel({
|
|
135
|
+
routes: [
|
|
136
|
+
POST("/deploy-request", async (request, { receive, waitUntil }) => {
|
|
137
|
+
const deployment = await request.json();
|
|
138
|
+
waitUntil(receive(mayi, {
|
|
139
|
+
message: `Review and deploy ${deployment.version}.`,
|
|
140
|
+
target: { mayiUserId: deployment.approverId },
|
|
141
|
+
auth: {
|
|
142
|
+
authenticator: "eden",
|
|
143
|
+
principalType: "service",
|
|
144
|
+
principalId: deployment.requestedBy,
|
|
145
|
+
attributes: {},
|
|
146
|
+
},
|
|
147
|
+
}));
|
|
148
|
+
return new Response("accepted", { status: 202 });
|
|
149
|
+
}),
|
|
150
|
+
],
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`target.mayiUserId` is optional. When supplied, it must be a 12-letter Mayi user
|
|
155
|
+
ID and is sent as the suggested approver. The caller supplies the initial
|
|
156
|
+
message, target, and Eve authentication context; the adapter owns the raw
|
|
157
|
+
continuation token and durable channel state.
|
|
158
|
+
|
|
159
|
+
## Callback route and resume semantics
|
|
160
|
+
|
|
161
|
+
`mayiChannel()` registers this route in the deployed Eve service:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
POST /eve/v1/mayi/approval-resolved
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Authors do not create that route, its URL, encrypted state, a correlation table,
|
|
168
|
+
or a signature verifier. The adapter builds the callback URL from the stable
|
|
169
|
+
public Eve origin. Register that exact HTTPS URL as an
|
|
170
|
+
entry in `approval_callback_uris` for the Eden/host OAuth client.
|
|
171
|
+
|
|
172
|
+
The explicit `POST()` route is intentional. Eve 0.24.2 compiles a channel
|
|
173
|
+
`route.path` verbatim; it does not prepend a channel namespace. Inventing a
|
|
174
|
+
`/channels/mayi/...` prefix registers the wrong OAuth callback and produces a
|
|
175
|
+
404 instead of a resume.
|
|
176
|
+
|
|
177
|
+
For every delivery, the adapter verifies Mayi's EdDSA JWS against Mayi's JWKS
|
|
178
|
+
before it touches encrypted state or resumes Eve. It then opens the authenticated
|
|
179
|
+
state and submits the response against the original Eve request ID and the
|
|
180
|
+
original channel-local continuation token. An `approved` result chooses Eve's
|
|
181
|
+
`approve` option. `denied`, `expired`, and `cancelled` choose `deny`, so the
|
|
182
|
+
parked session resumes but the gated tool does not run.
|
|
183
|
+
|
|
184
|
+
Callback delivery is at least once. A `2xx` response means Eve accepted the
|
|
185
|
+
resume or had already accepted the same verified event. The adapter does not
|
|
186
|
+
acknowledge before Eve accepts. Eve's continuation fence and event stream let
|
|
187
|
+
the adapter recognize an already-accepted resume, so retrying the same stable
|
|
188
|
+
event ID cannot execute the tool twice. Verification, decryption, or resume
|
|
189
|
+
failures return a non-`2xx` response so Mayi continues its durable retry policy.
|
|
190
|
+
The signed event and encrypted callback state remain acceptable for seven days
|
|
191
|
+
after resolution. Manual replay keeps the original event ID and occurrence time,
|
|
192
|
+
so operators must replay a dead letter within that window and consumers retain
|
|
193
|
+
the same duplicate-safety identity.
|
|
194
|
+
|
|
195
|
+
Hosts that already have a durable event store may pass `eventStore` with
|
|
196
|
+
`isProcessed(eventId)` and `markProcessed(eventId)` methods. The duplicate check
|
|
197
|
+
runs only after webhook verification, and `markProcessed` runs only after Eve
|
|
198
|
+
accepts the resume. A crash before acceptance therefore leaves the event
|
|
199
|
+
retryable. The hook is optional; ordinary Eden-generated integrations can rely
|
|
200
|
+
on Eve's durable acceptance check without adding a consumer database. The
|
|
201
|
+
advanced `webhookFetch` option can inject the fetch implementation used to load
|
|
202
|
+
Mayi's JWKS; normal deployments use the runtime's global `fetch`.
|
|
203
|
+
|
|
204
|
+
## Deployment configuration
|
|
205
|
+
|
|
206
|
+
The deployment host provisions:
|
|
207
|
+
|
|
208
|
+
- `EVE_PUBLIC_ORIGIN`: the stable public HTTPS origin of the deployed Eve agent,
|
|
209
|
+
such as `https://agent.example`. Do not use a transient preview URL.
|
|
210
|
+
- `MAYI_CALLBACK_STATE_KEY_ID`: the identifier for the current callback-state
|
|
211
|
+
encryption key.
|
|
212
|
+
- `MAYI_CALLBACK_STATE_KEY`: a stable base64url-encoded 32-byte encryption key.
|
|
213
|
+
- `MAYI_CALLBACK_STATE_PREVIOUS_KEYS` (optional): a JSON array of decrypt-only
|
|
214
|
+
`{ "kid", "key" }` entries retained while approvals and callback retries made
|
|
215
|
+
with older keys may still be outstanding.
|
|
216
|
+
- `MAYI_ORIGIN` (optional): the Mayi API and JWKS origin. It defaults to
|
|
217
|
+
`https://app.mayi.sh`.
|
|
218
|
+
|
|
219
|
+
Keep callback-state keys stable across process restarts and deploys. Rotate by
|
|
220
|
+
installing a new current key and retaining the old key in
|
|
221
|
+
`MAYI_CALLBACK_STATE_PREVIOUS_KEYS` until its approvals and the seven-day
|
|
222
|
+
callback acceptance window have elapsed. Never derive these keys from OAuth
|
|
223
|
+
credentials.
|
|
224
|
+
|
|
225
|
+
For local development, pass a public HTTPS tunnel origin as `publicOrigin` to
|
|
226
|
+
`mayiChannel()`, and register the resulting callback URL on the development
|
|
227
|
+
OAuth client. This override is refused in production. Mayi signing keys are
|
|
228
|
+
read from `${MAYI_ORIGIN}/.well-known/jwks.json` and cached with bounded refresh;
|
|
229
|
+
they are not copied into the agent's environment.
|
|
230
|
+
|
|
231
|
+
Never log decrypted callback state, continuation tokens, OAuth credentials,
|
|
232
|
+
receipts, or sensitive tool input.
|
|
233
|
+
|
|
234
|
+
## Troubleshooting
|
|
235
|
+
|
|
236
|
+
- **Public origin:** set `EVE_PUBLIC_ORIGIN` to one stable public HTTPS origin.
|
|
237
|
+
Vercel production can use `VERCEL_PROJECT_PRODUCTION_URL`; preview URLs,
|
|
238
|
+
localhost, paths, ports, and private hosts are refused.
|
|
239
|
+
- **Origin changes:** `approval_callback_uris` are immutable. Register a new
|
|
240
|
+
OAuth client with the new callback, reconnect through Authorization Code +
|
|
241
|
+
PKCE, confirm the new agent works, then revoke the old agent connection.
|
|
242
|
+
- **Local tunnels:** pass the tunnel origin through `publicOrigin` only in local
|
|
243
|
+
development and register its exact callback on a development OAuth client.
|
|
244
|
+
Tunnel rotation requires updating that development registration.
|
|
245
|
+
- **State rotation:** install a new callback-state key and retain old decrypt-only
|
|
246
|
+
keys until every outstanding approval plus Mayi's seven-day acceptance window has
|
|
247
|
+
elapsed. Unknown, tampered, expired, or wrong-key state fails closed.
|
|
248
|
+
- **Signing rotation:** Mayi publishes current and retained Ed25519 public keys at
|
|
249
|
+
`/.well-known/jwks.json`. Keep old signing public keys available through the
|
|
250
|
+
callback retry/event-age window; bounded JWKS refresh handles a newly seen key.
|
|
251
|
+
- **Retries and recovery:** non-`2xx` responses remain retryable according to
|
|
252
|
+
Mayi's outbox policy. Inspect the Mayi callback job, correct the receiver, and
|
|
253
|
+
replay only a `DEAD_LETTER` job through the authenticated replay endpoint. The
|
|
254
|
+
stable event ID makes duplicate delivery safe.
|
|
255
|
+
|
|
256
|
+
## Eve 0.24.2 limitation for unsupported input
|
|
257
|
+
|
|
258
|
+
Phase one supports approval-shaped confirmation requests only. A freeform or
|
|
259
|
+
select `ask_question` produces a descriptive `UnsupportedMayiInputError`; it is
|
|
260
|
+
never converted into an approval and is never treated as a successful no-op.
|
|
261
|
+
|
|
262
|
+
Eve 0.24.2 catches, logs, and swallows exceptions thrown by channel event
|
|
263
|
+
handlers, and exposes no public send/resume operation inside an event handler.
|
|
264
|
+
Consequently this rejection is visible in Eve's server logs but cannot currently
|
|
265
|
+
be propagated to the author or used to fail the session through Eve's public
|
|
266
|
+
contract; the session remains parked. Treat this as an unsupported-input error
|
|
267
|
+
and monitor Eve logs. It is a residual Eve contract gap, not approval behavior.
|
|
268
|
+
|
|
269
|
+
The package is ESM-only, supports Node.js 24 and later (matching Eve), and pins
|
|
270
|
+
its Eve peer to the tested `eve@0.24.2` contract.
|
|
271
|
+
|
|
272
|
+
Licensed under the [Apache License 2.0](LICENSE).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { GetAccessToken, MayiFetch, ArtefactMediaType, ArtefactBody, WebhookVerifierFetch, CallbackStateCodec } from '@mayiapp/sdk';
|
|
2
|
+
import { SessionHandle, Channel } from 'eve/channels';
|
|
3
|
+
import { SandboxSession } from 'eve/sandbox';
|
|
4
|
+
|
|
5
|
+
declare const MAYI_CALLBACK_PATH = "/eve/v1/mayi/approval-resolved";
|
|
6
|
+
interface MayiEnvironment {
|
|
7
|
+
readonly EVE_PUBLIC_ORIGIN?: string;
|
|
8
|
+
readonly MAYI_CALLBACK_STATE_KEY?: string;
|
|
9
|
+
readonly MAYI_CALLBACK_STATE_KEY_ID?: string;
|
|
10
|
+
readonly MAYI_CALLBACK_STATE_PREVIOUS_KEYS?: string;
|
|
11
|
+
readonly MAYI_ORIGIN?: string;
|
|
12
|
+
readonly NODE_ENV?: string;
|
|
13
|
+
readonly VERCEL_BRANCH_URL?: string;
|
|
14
|
+
readonly VERCEL_ENV?: string;
|
|
15
|
+
readonly VERCEL_PROJECT_PRODUCTION_URL?: string;
|
|
16
|
+
readonly VERCEL_URL?: string;
|
|
17
|
+
}
|
|
18
|
+
type MayiEveConfigurationErrorCode = "CALLBACK_STATE_KEY_UNAVAILABLE" | "INVALID_CALLBACK_STATE_KEYS" | "INVALID_CONFIG" | "INVALID_PUBLIC_ORIGIN" | "INVALID_RECEIVE_TARGET" | "PREVIEW_ORIGIN_REFUSED" | "PUBLIC_ORIGIN_UNAVAILABLE";
|
|
19
|
+
declare class MayiEveConfigurationError extends Error {
|
|
20
|
+
readonly code: MayiEveConfigurationErrorCode;
|
|
21
|
+
constructor(code: MayiEveConfigurationErrorCode, message: string);
|
|
22
|
+
}
|
|
23
|
+
interface ResolvePublicOriginOptions {
|
|
24
|
+
readonly environment?: MayiEnvironment;
|
|
25
|
+
/** Explicit local-development or tunnel origin. Ignored in production. */
|
|
26
|
+
readonly developmentOverride?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Resolves the stable origin Eve exposes publicly for durable callbacks. */
|
|
29
|
+
declare function resolvePublicOrigin(options?: ResolvePublicOriginOptions): string;
|
|
30
|
+
|
|
31
|
+
interface MayiReceiveTarget {
|
|
32
|
+
/** Mayi user to suggest as the approver for approvals started by this session. */
|
|
33
|
+
readonly mayiUserId?: string;
|
|
34
|
+
}
|
|
35
|
+
interface MayiChannelState {
|
|
36
|
+
/** The channel-local token passed to Eve send(); never derive this by stripping a namespace. */
|
|
37
|
+
rawContinuationToken: string | null;
|
|
38
|
+
target: MayiReceiveTarget | null;
|
|
39
|
+
/** Opaque callback material retained so a redelivered Eve event is retry-compatible. */
|
|
40
|
+
callbackRequests?: Record<string, MayiCallbackRequestState>;
|
|
41
|
+
}
|
|
42
|
+
interface MayiCallbackRequestState {
|
|
43
|
+
readonly state: string;
|
|
44
|
+
readonly approvalExpiresAt: string;
|
|
45
|
+
}
|
|
46
|
+
interface MayiWebhookEventStore {
|
|
47
|
+
/** Returns true only after Eve has accepted this event's resume. */
|
|
48
|
+
readonly isProcessed: (eventId: string) => boolean | Promise<boolean>;
|
|
49
|
+
/** Durably records an event after Eve has accepted its resume. */
|
|
50
|
+
readonly markProcessed: (eventId: string) => void | Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
type MayiArtefactMediaType = ArtefactMediaType;
|
|
53
|
+
type MayiArtefactBody = ArtefactBody;
|
|
54
|
+
interface MayiApprovalArtefact {
|
|
55
|
+
readonly filename: string;
|
|
56
|
+
readonly mediaType: MayiArtefactMediaType;
|
|
57
|
+
readonly body: MayiArtefactBody;
|
|
58
|
+
readonly size?: number;
|
|
59
|
+
}
|
|
60
|
+
interface MayiArtefactsContext {
|
|
61
|
+
readonly request: Readonly<EveInputRequest>;
|
|
62
|
+
readonly session: Readonly<Pick<SessionHandle, "id" | "continuationToken" | "auth">>;
|
|
63
|
+
readonly getSandbox: () => Promise<SandboxSession>;
|
|
64
|
+
readonly signal: AbortSignal;
|
|
65
|
+
}
|
|
66
|
+
type MayiArtefactsHook = (context: MayiArtefactsContext) => readonly MayiApprovalArtefact[] | null | undefined | Promise<readonly MayiApprovalArtefact[] | null | undefined>;
|
|
67
|
+
interface MayiChannelConfig {
|
|
68
|
+
readonly getAccessToken: GetAccessToken;
|
|
69
|
+
/** Mayi API origin. Defaults to MAYI_ORIGIN, then https://app.mayi.sh. */
|
|
70
|
+
readonly mayiOrigin?: string;
|
|
71
|
+
/** Explicit HTTPS origin for local development or a tunnel. Never used in production. */
|
|
72
|
+
readonly publicOrigin?: string;
|
|
73
|
+
readonly approvalExpiresInSeconds?: number;
|
|
74
|
+
readonly fetch?: MayiFetch;
|
|
75
|
+
/** Produces evidence before the gated tool executes. Omit to preserve the no-evidence path. */
|
|
76
|
+
readonly artefacts?: MayiArtefactsHook;
|
|
77
|
+
/** Maximum time for one request's hook and uploads. Defaults to 30 seconds. */
|
|
78
|
+
readonly artefactTimeoutMs?: number;
|
|
79
|
+
/** Optional durable duplicate fence. Both hooks must be backed by the same store. */
|
|
80
|
+
readonly eventStore?: MayiWebhookEventStore;
|
|
81
|
+
/** Advanced host/testing injection for Mayi's public webhook JWKS request. */
|
|
82
|
+
readonly webhookFetch?: WebhookVerifierFetch;
|
|
83
|
+
/** Advanced host/testing injection. Normal deployments use the host-provisioned key environment. */
|
|
84
|
+
readonly callbackStateCodec?: CallbackStateCodec;
|
|
85
|
+
/** Advanced host/testing injection for runtimes that do not expose process.env. */
|
|
86
|
+
readonly environment?: MayiEnvironment;
|
|
87
|
+
}
|
|
88
|
+
interface EveInputRequest {
|
|
89
|
+
readonly action: {
|
|
90
|
+
readonly kind: "tool-call";
|
|
91
|
+
readonly toolName: string;
|
|
92
|
+
readonly callId: string;
|
|
93
|
+
readonly input: Record<string, unknown>;
|
|
94
|
+
};
|
|
95
|
+
readonly allowFreeform?: boolean;
|
|
96
|
+
readonly display?: "confirmation" | "select" | "text";
|
|
97
|
+
readonly options?: readonly {
|
|
98
|
+
readonly id: string;
|
|
99
|
+
}[];
|
|
100
|
+
readonly prompt: string;
|
|
101
|
+
readonly requestId: string;
|
|
102
|
+
}
|
|
103
|
+
declare class UnsupportedMayiInputError extends Error {
|
|
104
|
+
readonly requestId: string;
|
|
105
|
+
constructor(requestId: string, display?: string);
|
|
106
|
+
}
|
|
107
|
+
declare function mayiChannel(config: MayiChannelConfig): Channel<MayiChannelState, MayiReceiveTarget>;
|
|
108
|
+
|
|
109
|
+
export { MAYI_CALLBACK_PATH, type MayiChannelConfig, type MayiChannelState, type MayiEnvironment, MayiEveConfigurationError, type MayiEveConfigurationErrorCode, type MayiReceiveTarget, type MayiWebhookEventStore, type ResolvePublicOriginOptions, UnsupportedMayiInputError, mayiChannel, resolvePublicOrigin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
// src/channel.ts
|
|
2
|
+
import {
|
|
3
|
+
CallbackStateError,
|
|
4
|
+
CALLBACK_ACCEPTANCE_WINDOW_SECONDS,
|
|
5
|
+
MAYI_SIGNATURE_HEADER,
|
|
6
|
+
MAX_WEBHOOK_BODY_BYTES,
|
|
7
|
+
MayiClient,
|
|
8
|
+
WebhookConfigurationError,
|
|
9
|
+
WebhookVerificationError,
|
|
10
|
+
createCallbackStateCodec,
|
|
11
|
+
createWebhookVerifier
|
|
12
|
+
} from "@mayiapp/sdk";
|
|
13
|
+
import {
|
|
14
|
+
POST,
|
|
15
|
+
defineChannel
|
|
16
|
+
} from "eve/channels";
|
|
17
|
+
|
|
18
|
+
// src/origin.ts
|
|
19
|
+
var MAYI_CALLBACK_PATH = "/eve/v1/mayi/approval-resolved";
|
|
20
|
+
var MayiEveConfigurationError = class extends Error {
|
|
21
|
+
code;
|
|
22
|
+
constructor(code, message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "MayiEveConfigurationError";
|
|
25
|
+
this.code = code;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function runtimeEnvironment() {
|
|
29
|
+
const runtime = globalThis;
|
|
30
|
+
return runtime.process?.env ?? {};
|
|
31
|
+
}
|
|
32
|
+
function hostnameFromEnvironmentUrl(value) {
|
|
33
|
+
if (!value) return void 0;
|
|
34
|
+
try {
|
|
35
|
+
const candidate = value.includes("://") ? value : `https://${value}`;
|
|
36
|
+
return new URL(candidate).hostname.toLowerCase();
|
|
37
|
+
} catch {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isNonPublicHostname(hostname) {
|
|
42
|
+
const lower = hostname.toLowerCase();
|
|
43
|
+
if (lower === "localhost" || lower.endsWith(".localhost") || lower.endsWith(".local") || lower.endsWith(".internal") || !lower.includes(".")) return true;
|
|
44
|
+
return /^\d{1,3}(?:\.\d{1,3}){3}$/.test(lower) || lower.includes(":");
|
|
45
|
+
}
|
|
46
|
+
function normalizePublicHttpsOrigin(value) {
|
|
47
|
+
try {
|
|
48
|
+
const url = new URL(value);
|
|
49
|
+
if (url.protocol !== "https:" || url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.port || isNonPublicHostname(url.hostname)) throw new Error("invalid origin");
|
|
50
|
+
return url.origin;
|
|
51
|
+
} catch {
|
|
52
|
+
throw new MayiEveConfigurationError(
|
|
53
|
+
"INVALID_PUBLIC_ORIGIN",
|
|
54
|
+
"The Eve public origin must be a public HTTPS origin without credentials, a path, query, fragment, or non-default port"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function assertNotTransientPreview(origin, environment) {
|
|
59
|
+
const hostname = new URL(origin).hostname.toLowerCase();
|
|
60
|
+
const productionHostname = hostnameFromEnvironmentUrl(environment.VERCEL_PROJECT_PRODUCTION_URL);
|
|
61
|
+
const transientHostnames = [environment.VERCEL_URL, environment.VERCEL_BRANCH_URL].map(hostnameFromEnvironmentUrl).filter((item) => item !== void 0 && item !== productionHostname);
|
|
62
|
+
if (transientHostnames.includes(hostname)) {
|
|
63
|
+
throw new MayiEveConfigurationError(
|
|
64
|
+
"PREVIEW_ORIGIN_REFUSED",
|
|
65
|
+
"Transient Vercel preview URLs cannot be used for durable Mayi approval callbacks"
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function resolvePublicOrigin(options = {}) {
|
|
70
|
+
const environment = options.environment ?? runtimeEnvironment();
|
|
71
|
+
if (environment.EVE_PUBLIC_ORIGIN !== void 0) {
|
|
72
|
+
const origin = normalizePublicHttpsOrigin(environment.EVE_PUBLIC_ORIGIN);
|
|
73
|
+
assertNotTransientPreview(origin, environment);
|
|
74
|
+
return origin;
|
|
75
|
+
}
|
|
76
|
+
if (environment.VERCEL_ENV === "production" && environment.VERCEL_PROJECT_PRODUCTION_URL) {
|
|
77
|
+
const value = environment.VERCEL_PROJECT_PRODUCTION_URL;
|
|
78
|
+
const origin = normalizePublicHttpsOrigin(value.includes("://") ? value : `https://${value}`);
|
|
79
|
+
assertNotTransientPreview(origin, environment);
|
|
80
|
+
return origin;
|
|
81
|
+
}
|
|
82
|
+
const production = environment.NODE_ENV === "production" || environment.VERCEL_ENV === "production";
|
|
83
|
+
if (!production && options.developmentOverride !== void 0) {
|
|
84
|
+
const origin = normalizePublicHttpsOrigin(options.developmentOverride);
|
|
85
|
+
assertNotTransientPreview(origin, environment);
|
|
86
|
+
return origin;
|
|
87
|
+
}
|
|
88
|
+
throw new MayiEveConfigurationError(
|
|
89
|
+
"PUBLIC_ORIGIN_UNAVAILABLE",
|
|
90
|
+
"A stable public Eve origin is required; provision EVE_PUBLIC_ORIGIN for this deployment"
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
function getRuntimeEnvironment() {
|
|
94
|
+
return runtimeEnvironment();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/channel.ts
|
|
98
|
+
var DEFAULT_MAYI_ORIGIN = "https://app.mayi.sh";
|
|
99
|
+
var DEFAULT_APPROVAL_EXPIRES_IN_SECONDS = 60 * 60;
|
|
100
|
+
var MAYI_USER_ID_PATTERN = /^[A-Za-z]{12}$/;
|
|
101
|
+
var MAX_CONTINUATION_TOKEN_LENGTH = 4096;
|
|
102
|
+
var MAX_CORRELATION_ID_LENGTH = 512;
|
|
103
|
+
var MAX_EXPIRY_LENGTH = 64;
|
|
104
|
+
var ACCEPTANCE_RECONCILIATION_TIMEOUT_MS = 2e3;
|
|
105
|
+
var DEFAULT_ARTEFACT_TIMEOUT_MS = 3e4;
|
|
106
|
+
var MAX_ARTEFACTS = 20;
|
|
107
|
+
var ARTEFACT_CONCURRENCY = 3;
|
|
108
|
+
var MAX_CALLBACK_BODY_BYTES = MAX_WEBHOOK_BODY_BYTES;
|
|
109
|
+
var Semaphore = class {
|
|
110
|
+
constructor(maximum) {
|
|
111
|
+
this.maximum = maximum;
|
|
112
|
+
}
|
|
113
|
+
maximum;
|
|
114
|
+
active = 0;
|
|
115
|
+
waiting = [];
|
|
116
|
+
async run(task) {
|
|
117
|
+
if (this.active >= this.maximum) await new Promise((resolve) => this.waiting.push(resolve));
|
|
118
|
+
this.active++;
|
|
119
|
+
try {
|
|
120
|
+
return await task();
|
|
121
|
+
} finally {
|
|
122
|
+
this.active--;
|
|
123
|
+
this.waiting.shift()?.();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var UnsupportedMayiInputError = class extends Error {
|
|
128
|
+
requestId;
|
|
129
|
+
constructor(requestId, display = "unspecified") {
|
|
130
|
+
super(
|
|
131
|
+
`@mayiapp/eve supports only tool approval confirmations; Eve input request "${requestId}" uses unsupported display "${display}"`
|
|
132
|
+
);
|
|
133
|
+
this.name = "UnsupportedMayiInputError";
|
|
134
|
+
this.requestId = requestId;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
function parsePreviousKeys(value) {
|
|
138
|
+
if (!value) return [];
|
|
139
|
+
let parsed;
|
|
140
|
+
try {
|
|
141
|
+
parsed = JSON.parse(value);
|
|
142
|
+
} catch {
|
|
143
|
+
throw new MayiEveConfigurationError(
|
|
144
|
+
"INVALID_CALLBACK_STATE_KEYS",
|
|
145
|
+
"MAYI_CALLBACK_STATE_PREVIOUS_KEYS must be a JSON array of callback-state keys"
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
if (!Array.isArray(parsed) || parsed.some((item) => !item || typeof item !== "object" || Array.isArray(item) || Object.keys(item).some((key) => key !== "kid" && key !== "key") || typeof item.kid !== "string" || typeof item.key !== "string")) {
|
|
149
|
+
throw new MayiEveConfigurationError(
|
|
150
|
+
"INVALID_CALLBACK_STATE_KEYS",
|
|
151
|
+
"MAYI_CALLBACK_STATE_PREVIOUS_KEYS must be a JSON array of callback-state keys"
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return parsed;
|
|
155
|
+
}
|
|
156
|
+
async function callbackStateCodecFromEnvironment(environment) {
|
|
157
|
+
const kid = environment.MAYI_CALLBACK_STATE_KEY_ID;
|
|
158
|
+
const key = environment.MAYI_CALLBACK_STATE_KEY;
|
|
159
|
+
if (!kid || !key) {
|
|
160
|
+
throw new MayiEveConfigurationError(
|
|
161
|
+
"CALLBACK_STATE_KEY_UNAVAILABLE",
|
|
162
|
+
"The host must provision MAYI_CALLBACK_STATE_KEY_ID and MAYI_CALLBACK_STATE_KEY"
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
return await createCallbackStateCodec({
|
|
167
|
+
currentKey: { kid, key },
|
|
168
|
+
previousKeys: parsePreviousKeys(environment.MAYI_CALLBACK_STATE_PREVIOUS_KEYS),
|
|
169
|
+
maximumRetryWindowSeconds: CALLBACK_ACCEPTANCE_WINDOW_SECONDS
|
|
170
|
+
});
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (error instanceof MayiEveConfigurationError) throw error;
|
|
173
|
+
throw new MayiEveConfigurationError(
|
|
174
|
+
"INVALID_CALLBACK_STATE_KEYS",
|
|
175
|
+
"The host-provisioned callback-state key configuration is invalid"
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function createRuntime(config, dependencies = {}) {
|
|
180
|
+
if (!config || typeof config !== "object" || typeof config.getAccessToken !== "function") {
|
|
181
|
+
throw new MayiEveConfigurationError("INVALID_CONFIG", "mayiChannel requires getAccessToken");
|
|
182
|
+
}
|
|
183
|
+
const expiresInSeconds = config.approvalExpiresInSeconds ?? DEFAULT_APPROVAL_EXPIRES_IN_SECONDS;
|
|
184
|
+
if (!Number.isInteger(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > 7 * 24 * 60 * 60) {
|
|
185
|
+
throw new MayiEveConfigurationError(
|
|
186
|
+
"INVALID_CONFIG",
|
|
187
|
+
"approvalExpiresInSeconds must be an integer between 60 and 604800"
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (config.eventStore !== void 0 && (!config.eventStore || typeof config.eventStore !== "object" || typeof config.eventStore.isProcessed !== "function" || typeof config.eventStore.markProcessed !== "function")) {
|
|
191
|
+
throw new MayiEveConfigurationError(
|
|
192
|
+
"INVALID_CONFIG",
|
|
193
|
+
"eventStore must provide both isProcessed and markProcessed"
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
const artefactTimeoutMs = config.artefactTimeoutMs ?? DEFAULT_ARTEFACT_TIMEOUT_MS;
|
|
197
|
+
if (!Number.isInteger(artefactTimeoutMs) || artefactTimeoutMs < 1 || artefactTimeoutMs > 5 * 60 * 1e3) {
|
|
198
|
+
throw new MayiEveConfigurationError(
|
|
199
|
+
"INVALID_CONFIG",
|
|
200
|
+
"artefactTimeoutMs must be an integer between 1 and 300000"
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (config.artefacts !== void 0 && typeof config.artefacts !== "function") {
|
|
204
|
+
throw new MayiEveConfigurationError("INVALID_CONFIG", "artefacts must be a function");
|
|
205
|
+
}
|
|
206
|
+
const environment = config.environment ?? getRuntimeEnvironment();
|
|
207
|
+
const mayiOrigin = config.mayiOrigin ?? environment.MAYI_ORIGIN ?? DEFAULT_MAYI_ORIGIN;
|
|
208
|
+
const client = new MayiClient({
|
|
209
|
+
origin: mayiOrigin,
|
|
210
|
+
getAccessToken: config.getAccessToken,
|
|
211
|
+
...config.fetch === void 0 ? {} : { fetch: config.fetch }
|
|
212
|
+
});
|
|
213
|
+
let codecPromise;
|
|
214
|
+
let verifier;
|
|
215
|
+
return {
|
|
216
|
+
...config.artefacts === void 0 ? {} : { artefacts: config.artefacts },
|
|
217
|
+
artefactSemaphore: new Semaphore(ARTEFACT_CONCURRENCY),
|
|
218
|
+
artefactTimeoutMs,
|
|
219
|
+
client,
|
|
220
|
+
environment,
|
|
221
|
+
...config.eventStore === void 0 ? {} : { eventStore: config.eventStore },
|
|
222
|
+
expiresInSeconds,
|
|
223
|
+
now: dependencies.now ?? Date.now,
|
|
224
|
+
...config.publicOrigin === void 0 ? {} : { publicOriginOverride: config.publicOrigin },
|
|
225
|
+
codec() {
|
|
226
|
+
codecPromise ??= config.callbackStateCodec ? Promise.resolve(config.callbackStateCodec) : callbackStateCodecFromEnvironment(environment);
|
|
227
|
+
return codecPromise;
|
|
228
|
+
},
|
|
229
|
+
verifier() {
|
|
230
|
+
verifier ??= createWebhookVerifier({
|
|
231
|
+
mayiOrigin,
|
|
232
|
+
maximumEventAgeSeconds: CALLBACK_ACCEPTANCE_WINDOW_SECONDS,
|
|
233
|
+
now: dependencies.now ?? Date.now,
|
|
234
|
+
...config.webhookFetch === void 0 ? {} : { fetch: config.webhookFetch },
|
|
235
|
+
...config.eventStore === void 0 ? {} : { isProcessed: config.eventStore.isProcessed }
|
|
236
|
+
});
|
|
237
|
+
return verifier;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function isApprovalRequest(request) {
|
|
242
|
+
if (request.display !== "confirmation" || request.allowFreeform === true) return false;
|
|
243
|
+
const optionIds = request.options?.map((option) => option.id) ?? [];
|
|
244
|
+
return optionIds.length === 2 && optionIds.includes("approve") && optionIds.includes("deny");
|
|
245
|
+
}
|
|
246
|
+
function bytesToBase64Url(bytes) {
|
|
247
|
+
let binary = "";
|
|
248
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
249
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
250
|
+
}
|
|
251
|
+
async function createMayiIdempotencyKey(sessionId, requestId) {
|
|
252
|
+
const material = new TextEncoder().encode(JSON.stringify(["mayi-eve-v1", sessionId, requestId]));
|
|
253
|
+
const digest = await crypto.subtle.digest("SHA-256", material);
|
|
254
|
+
return `mayi:eve:v1:${bytesToBase64Url(new Uint8Array(digest))}`;
|
|
255
|
+
}
|
|
256
|
+
async function submitOneRequest(request, channel, context, runtime) {
|
|
257
|
+
if (!isApprovalRequest(request)) {
|
|
258
|
+
throw new UnsupportedMayiInputError(request.requestId, request.display);
|
|
259
|
+
}
|
|
260
|
+
const rawContinuationToken = channel.state.rawContinuationToken;
|
|
261
|
+
if (!rawContinuationToken || !channel.state.target) {
|
|
262
|
+
throw new MayiEveConfigurationError(
|
|
263
|
+
"INVALID_CONFIG",
|
|
264
|
+
"The Mayi channel is missing its durable receive state"
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
let callbackRequest = channel.state.callbackRequests?.[request.requestId];
|
|
268
|
+
if (!callbackRequest) {
|
|
269
|
+
const now = runtime.now();
|
|
270
|
+
const approvalExpiresAt = new Date(now + runtime.expiresInSeconds * 1e3).toISOString();
|
|
271
|
+
const stateExpiresAt = new Date(
|
|
272
|
+
now + (runtime.expiresInSeconds + CALLBACK_ACCEPTANCE_WINDOW_SECONDS) * 1e3
|
|
273
|
+
).toISOString();
|
|
274
|
+
const codec = await runtime.codec();
|
|
275
|
+
const state = await codec.seal({
|
|
276
|
+
version: 1,
|
|
277
|
+
rawContinuationToken,
|
|
278
|
+
requestId: request.requestId,
|
|
279
|
+
sessionId: context.session.id,
|
|
280
|
+
expiresAt: stateExpiresAt
|
|
281
|
+
}, { approvalExpiresAt });
|
|
282
|
+
callbackRequest = { state, approvalExpiresAt };
|
|
283
|
+
channel.state.callbackRequests ??= {};
|
|
284
|
+
channel.state.callbackRequests[request.requestId] = callbackRequest;
|
|
285
|
+
}
|
|
286
|
+
const publicOrigin = resolvePublicOrigin({
|
|
287
|
+
environment: runtime.environment,
|
|
288
|
+
...runtime.publicOriginOverride === void 0 ? {} : { developmentOverride: runtime.publicOriginOverride }
|
|
289
|
+
});
|
|
290
|
+
const idempotencyKey = await createMayiIdempotencyKey(context.session.id, request.requestId);
|
|
291
|
+
const artefactIds = await stageRequestArtefacts(request, channel, context, runtime, idempotencyKey);
|
|
292
|
+
await runtime.client.approvals.request({
|
|
293
|
+
action: request.action,
|
|
294
|
+
explanation: request.prompt,
|
|
295
|
+
expiresInSeconds: runtime.expiresInSeconds,
|
|
296
|
+
...channel.state.target.mayiUserId === void 0 ? {} : { suggestedApproverId: channel.state.target.mayiUserId },
|
|
297
|
+
callback: {
|
|
298
|
+
url: `${publicOrigin}${MAYI_CALLBACK_PATH}`,
|
|
299
|
+
state: callbackRequest.state
|
|
300
|
+
},
|
|
301
|
+
...artefactIds === void 0 ? {} : { artefactIds }
|
|
302
|
+
}, { idempotencyKey });
|
|
303
|
+
}
|
|
304
|
+
async function stageRequestArtefacts(request, channel, context, runtime, idempotencyKey) {
|
|
305
|
+
if (!runtime.artefacts) return void 0;
|
|
306
|
+
if (!channel.session || !context.getSandbox) {
|
|
307
|
+
throw new MayiEveConfigurationError("INVALID_CONFIG", "Eve did not provide the artefact hook context");
|
|
308
|
+
}
|
|
309
|
+
const session = channel.session;
|
|
310
|
+
const getSandbox = context.getSandbox;
|
|
311
|
+
const controller = new AbortController();
|
|
312
|
+
const timeout = setTimeout(() => controller.abort(new Error("Mayi artefact preparation timed out")), runtime.artefactTimeoutMs);
|
|
313
|
+
try {
|
|
314
|
+
return await Promise.race([
|
|
315
|
+
runtime.artefactSemaphore.run(async () => {
|
|
316
|
+
const artefacts = await runtime.artefacts({
|
|
317
|
+
request,
|
|
318
|
+
session,
|
|
319
|
+
getSandbox,
|
|
320
|
+
signal: controller.signal
|
|
321
|
+
});
|
|
322
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
323
|
+
if (artefacts == null || artefacts.length === 0) return void 0;
|
|
324
|
+
if (!Array.isArray(artefacts) || artefacts.length > MAX_ARTEFACTS) {
|
|
325
|
+
throw new MayiEveConfigurationError("INVALID_CONFIG", "artefacts must return at most 20 items");
|
|
326
|
+
}
|
|
327
|
+
const ids = [];
|
|
328
|
+
for (const [ordinal, artefact] of artefacts.entries()) {
|
|
329
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
330
|
+
const staged = await runtime.client.stageRequestArtefact(
|
|
331
|
+
idempotencyKey,
|
|
332
|
+
ordinal,
|
|
333
|
+
artefact.filename,
|
|
334
|
+
artefact.mediaType,
|
|
335
|
+
artefact.body,
|
|
336
|
+
{
|
|
337
|
+
signal: controller.signal,
|
|
338
|
+
...artefact.size === void 0 ? {} : { size: artefact.size }
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
ids.push(staged.id);
|
|
342
|
+
}
|
|
343
|
+
return ids;
|
|
344
|
+
}),
|
|
345
|
+
new Promise((_, reject) => {
|
|
346
|
+
controller.signal.addEventListener("abort", () => reject(controller.signal.reason), { once: true });
|
|
347
|
+
})
|
|
348
|
+
]);
|
|
349
|
+
} finally {
|
|
350
|
+
clearTimeout(timeout);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function createInputRequestedHandler(runtime) {
|
|
354
|
+
return async (data, channel, context) => {
|
|
355
|
+
const results = await Promise.allSettled(
|
|
356
|
+
data.requests.map((request) => submitOneRequest(request, channel, context, runtime))
|
|
357
|
+
);
|
|
358
|
+
const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
359
|
+
if (failures.length) throw new AggregateError(failures, "One or more Mayi approval requests failed");
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function genericResponse(status, message) {
|
|
363
|
+
return Response.json({ error: message }, {
|
|
364
|
+
status,
|
|
365
|
+
headers: { "cache-control": "no-store" }
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
async function readCallbackBody(request) {
|
|
369
|
+
const contentLength = request.headers.get("content-length");
|
|
370
|
+
if (contentLength !== null && (!/^\d+$/.test(contentLength) || Number(contentLength) > MAX_CALLBACK_BODY_BYTES)) throw new Error("Invalid callback request");
|
|
371
|
+
if (!request.body) return "";
|
|
372
|
+
const reader = request.body.getReader();
|
|
373
|
+
const chunks = [];
|
|
374
|
+
let length = 0;
|
|
375
|
+
try {
|
|
376
|
+
while (true) {
|
|
377
|
+
const { done, value } = await reader.read();
|
|
378
|
+
if (done) break;
|
|
379
|
+
length += value.byteLength;
|
|
380
|
+
if (length > MAX_CALLBACK_BODY_BYTES) {
|
|
381
|
+
await reader.cancel();
|
|
382
|
+
throw new Error("Invalid callback request");
|
|
383
|
+
}
|
|
384
|
+
chunks.push(value);
|
|
385
|
+
}
|
|
386
|
+
} finally {
|
|
387
|
+
reader.releaseLock();
|
|
388
|
+
}
|
|
389
|
+
const bytes = new Uint8Array(length);
|
|
390
|
+
let offset = 0;
|
|
391
|
+
for (const chunk of chunks) {
|
|
392
|
+
bytes.set(chunk, offset);
|
|
393
|
+
offset += chunk.byteLength;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
397
|
+
} catch {
|
|
398
|
+
throw new Error("Invalid callback request");
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function validBoundedString(value, maximumLength) {
|
|
402
|
+
return typeof value === "string" && value.length > 0 && value.length <= maximumLength;
|
|
403
|
+
}
|
|
404
|
+
function parseContinuationState(value, currentTime) {
|
|
405
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length !== 5 || value.version !== 1 || !validBoundedString(
|
|
406
|
+
value.rawContinuationToken,
|
|
407
|
+
MAX_CONTINUATION_TOKEN_LENGTH
|
|
408
|
+
) || !validBoundedString(value.requestId, MAX_CORRELATION_ID_LENGTH) || !validBoundedString(value.sessionId, MAX_CORRELATION_ID_LENGTH) || !validBoundedString(value.expiresAt, MAX_EXPIRY_LENGTH)) throw new CallbackStateError("INVALID_STATE");
|
|
409
|
+
const state = value;
|
|
410
|
+
const expiresAt = Date.parse(state.expiresAt);
|
|
411
|
+
if (!Number.isFinite(expiresAt)) throw new CallbackStateError("INVALID_STATE");
|
|
412
|
+
if (expiresAt <= currentTime) throw new CallbackStateError("EXPIRED");
|
|
413
|
+
return state;
|
|
414
|
+
}
|
|
415
|
+
async function requestWasAccepted(getSession, sessionId, requestId) {
|
|
416
|
+
let callId;
|
|
417
|
+
try {
|
|
418
|
+
const stream = await getSession(sessionId).getEventStream();
|
|
419
|
+
const reader = stream.getReader();
|
|
420
|
+
try {
|
|
421
|
+
const deadline = Date.now() + ACCEPTANCE_RECONCILIATION_TIMEOUT_MS;
|
|
422
|
+
while (true) {
|
|
423
|
+
const remaining = deadline - Date.now();
|
|
424
|
+
if (remaining <= 0) {
|
|
425
|
+
await reader.cancel();
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
let timeout;
|
|
429
|
+
const result = await Promise.race([
|
|
430
|
+
reader.read(),
|
|
431
|
+
new Promise((resolve) => {
|
|
432
|
+
timeout = setTimeout(() => resolve(null), remaining);
|
|
433
|
+
})
|
|
434
|
+
]).finally(() => clearTimeout(timeout));
|
|
435
|
+
if (result === null) {
|
|
436
|
+
await reader.cancel();
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
const { done, value } = result;
|
|
440
|
+
if (done) return false;
|
|
441
|
+
if (value.type === "input.requested") {
|
|
442
|
+
const request = value.data.requests.find((candidate) => candidate.requestId === requestId);
|
|
443
|
+
if (request?.action.kind === "tool-call") callId = request.action.callId;
|
|
444
|
+
} else if (callId !== void 0 && value.type === "action.result" && value.data.result.kind === "tool-result" && value.data.result.callId === callId) {
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
} finally {
|
|
449
|
+
reader.releaseLock();
|
|
450
|
+
}
|
|
451
|
+
} catch {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function markProcessed(eventId, runtime) {
|
|
456
|
+
if (!runtime.eventStore) return true;
|
|
457
|
+
try {
|
|
458
|
+
await runtime.eventStore.markProcessed(eventId);
|
|
459
|
+
return true;
|
|
460
|
+
} catch {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
async function alreadyProcessed(eventId, runtime) {
|
|
465
|
+
if (!runtime.eventStore) return false;
|
|
466
|
+
try {
|
|
467
|
+
return await runtime.eventStore.isProcessed(eventId) === true;
|
|
468
|
+
} catch {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function createApprovalResolvedHandler(runtime) {
|
|
473
|
+
return async (request, args) => {
|
|
474
|
+
let body;
|
|
475
|
+
try {
|
|
476
|
+
body = await readCallbackBody(request);
|
|
477
|
+
} catch {
|
|
478
|
+
return genericResponse(400, "Invalid callback request");
|
|
479
|
+
}
|
|
480
|
+
let verification;
|
|
481
|
+
try {
|
|
482
|
+
verification = await runtime.verifier().verify({
|
|
483
|
+
body,
|
|
484
|
+
signature: request.headers.get(MAYI_SIGNATURE_HEADER)
|
|
485
|
+
});
|
|
486
|
+
} catch (error) {
|
|
487
|
+
if (error instanceof WebhookConfigurationError) {
|
|
488
|
+
return genericResponse(503, "Callback verification is temporarily unavailable");
|
|
489
|
+
}
|
|
490
|
+
if (error instanceof WebhookVerificationError && (error.code === "KEY_SET_UNAVAILABLE" || error.code === "DUPLICATE_CHECK_FAILED")) return genericResponse(503, "Callback verification is temporarily unavailable");
|
|
491
|
+
return genericResponse(401, "Callback verification failed");
|
|
492
|
+
}
|
|
493
|
+
if (verification.duplicate) {
|
|
494
|
+
return new Response(null, { status: 208, headers: { "cache-control": "no-store" } });
|
|
495
|
+
}
|
|
496
|
+
let state;
|
|
497
|
+
let codec;
|
|
498
|
+
try {
|
|
499
|
+
codec = await runtime.codec();
|
|
500
|
+
} catch {
|
|
501
|
+
return genericResponse(503, "Callback state handling is temporarily unavailable");
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
state = parseContinuationState(
|
|
505
|
+
await codec.open(verification.event.state),
|
|
506
|
+
runtime.now()
|
|
507
|
+
);
|
|
508
|
+
} catch {
|
|
509
|
+
return genericResponse(400, "Callback state is invalid");
|
|
510
|
+
}
|
|
511
|
+
const optionId = verification.event.status === "approved" ? "approve" : "deny";
|
|
512
|
+
try {
|
|
513
|
+
const session = await args.send({
|
|
514
|
+
inputResponses: [{ requestId: state.requestId, optionId }]
|
|
515
|
+
}, {
|
|
516
|
+
auth: null,
|
|
517
|
+
continuationToken: state.rawContinuationToken,
|
|
518
|
+
state: { rawContinuationToken: state.rawContinuationToken, target: null }
|
|
519
|
+
});
|
|
520
|
+
if (session.id !== state.sessionId) throw new Error("resume session mismatch");
|
|
521
|
+
} catch {
|
|
522
|
+
if (await alreadyProcessed(verification.event.id, runtime)) {
|
|
523
|
+
return new Response(null, { status: 208, headers: { "cache-control": "no-store" } });
|
|
524
|
+
}
|
|
525
|
+
if (!await requestWasAccepted(args.getSession, state.sessionId, state.requestId)) {
|
|
526
|
+
return genericResponse(503, "Eve did not accept the callback resume");
|
|
527
|
+
}
|
|
528
|
+
if (!await markProcessed(verification.event.id, runtime)) {
|
|
529
|
+
return genericResponse(503, "Callback acknowledgement is temporarily unavailable");
|
|
530
|
+
}
|
|
531
|
+
return new Response(null, { status: 208, headers: { "cache-control": "no-store" } });
|
|
532
|
+
}
|
|
533
|
+
if (!await markProcessed(verification.event.id, runtime)) {
|
|
534
|
+
return genericResponse(503, "Callback acknowledgement is temporarily unavailable");
|
|
535
|
+
}
|
|
536
|
+
return new Response(null, { status: 202, headers: { "cache-control": "no-store" } });
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function createRawContinuationToken() {
|
|
540
|
+
if (!globalThis.crypto || typeof globalThis.crypto.randomUUID !== "function") {
|
|
541
|
+
throw new MayiEveConfigurationError("INVALID_CONFIG", "A cryptographically secure random UUID source is required");
|
|
542
|
+
}
|
|
543
|
+
return `mayi:${globalThis.crypto.randomUUID()}`;
|
|
544
|
+
}
|
|
545
|
+
function mayiChannel(config) {
|
|
546
|
+
const runtime = createRuntime(config);
|
|
547
|
+
const inputRequested = createInputRequestedHandler(runtime);
|
|
548
|
+
return defineChannel({
|
|
549
|
+
kindHint: "mayi",
|
|
550
|
+
state: { rawContinuationToken: null, target: null, callbackRequests: {} },
|
|
551
|
+
context(state, session) {
|
|
552
|
+
return {
|
|
553
|
+
state,
|
|
554
|
+
session: { id: session.id, continuationToken: session.continuationToken, auth: session.auth }
|
|
555
|
+
};
|
|
556
|
+
},
|
|
557
|
+
routes: [POST(MAYI_CALLBACK_PATH, createApprovalResolvedHandler(runtime))],
|
|
558
|
+
async receive(input, { send }) {
|
|
559
|
+
const mayiUserId = input.target.mayiUserId;
|
|
560
|
+
if (mayiUserId !== void 0 && !MAYI_USER_ID_PATTERN.test(mayiUserId)) {
|
|
561
|
+
throw new MayiEveConfigurationError(
|
|
562
|
+
"INVALID_RECEIVE_TARGET",
|
|
563
|
+
"target.mayiUserId must be exactly 12 ASCII letters"
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
const rawContinuationToken = createRawContinuationToken();
|
|
567
|
+
const target = mayiUserId === void 0 ? {} : { mayiUserId };
|
|
568
|
+
return send(input.message, {
|
|
569
|
+
auth: input.auth,
|
|
570
|
+
continuationToken: rawContinuationToken,
|
|
571
|
+
state: { rawContinuationToken, target, callbackRequests: {} }
|
|
572
|
+
});
|
|
573
|
+
},
|
|
574
|
+
events: { "input.requested": inputRequested }
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
export {
|
|
578
|
+
MAYI_CALLBACK_PATH,
|
|
579
|
+
MayiEveConfigurationError,
|
|
580
|
+
UnsupportedMayiInputError,
|
|
581
|
+
mayiChannel,
|
|
582
|
+
resolvePublicOrigin
|
|
583
|
+
};
|
|
584
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["https://raw.githubusercontent.com/asiraky/mayi/main/packages/eve/src/channel.ts","https://raw.githubusercontent.com/asiraky/mayi/main/packages/eve/src/origin.ts"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mayiapp/eve",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Durable Mayi approval channel for Eve agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"license": "Apache-2.0",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/asiraky/mayi",
|
|
24
|
+
"directory": "packages/eve"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@mayiapp/sdk": "^0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"eve": "0.24.2"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"eve": "0.24.2",
|
|
40
|
+
"tsup": "^8.5.1",
|
|
41
|
+
"typescript": "^5.9.0",
|
|
42
|
+
"zod": "^4.4.3"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup && node ./scripts/normalize-source-maps.mjs",
|
|
46
|
+
"test:harness": "cd test-fixtures/approval-harness && eve eval --skip-report --timeout 30000 --max-concurrency 1",
|
|
47
|
+
"test:package": "node ./scripts/test-package.mjs",
|
|
48
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
49
|
+
}
|
|
50
|
+
}
|