@fastagent-sh/fastagent 0.29.0 → 0.30.1
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 +9 -4
- package/dist/atomic-write.d.ts +4 -5
- package/dist/atomic-write.js +4 -5
- package/dist/authoring.d.ts +32 -15
- package/dist/authoring.js +147 -127
- package/dist/channels/agentcore-protocol.d.ts +8 -3
- package/dist/channels/agentcore-protocol.js +3 -1
- package/dist/channels/agentcore-service.d.ts +1 -0
- package/dist/channels/agentcore-service.js +14 -4
- package/dist/channels/agentcore.d.ts +9 -0
- package/dist/channels/agentcore.js +29 -4
- package/dist/channels/context.d.ts +2 -0
- package/dist/channels/context.js +5 -1
- package/dist/channels/feishu/feishu-api.d.ts +2 -1
- package/dist/channels/feishu/feishu.d.ts +0 -3
- package/dist/channels/feishu/feishu.js +10 -10
- package/dist/channels/feishu/register-app.js +3 -5
- package/dist/channels/feishu/scaffold/channel.ts +32 -34
- package/dist/channels/feishu/scaffold/feishu-send.ts +5 -5
- package/dist/channels/feishu/scaffold/feishu-threads.ts +3 -3
- package/dist/channels/feishu/setup-mode.d.ts +2 -12
- package/dist/channels/feishu/setup-mode.js +2 -22
- package/dist/channels/feishu/setup.d.ts +12 -0
- package/dist/channels/feishu/setup.js +197 -0
- package/dist/channels/kit/abortable.d.ts +8 -0
- package/dist/channels/kit/abortable.js +22 -0
- package/dist/channels/lark/lark.d.ts +0 -3
- package/dist/channels/lark/lark.js +0 -5
- package/dist/channels/lark/scaffold/channel.ts +33 -35
- package/dist/channels/lark/scaffold/lark-send.ts +5 -5
- package/dist/channels/lark/scaffold/lark-threads.ts +3 -3
- package/dist/channels/lark/setup.d.ts +9 -0
- package/dist/channels/lark/setup.js +57 -0
- package/dist/channels/setup.d.ts +112 -0
- package/dist/channels/setup.js +31 -0
- package/dist/channels/slack/history.js +1 -1
- package/dist/channels/slack/manifest.d.ts +17 -7
- package/dist/channels/slack/manifest.js +12 -16
- package/dist/channels/slack/scaffold/channel.ts +44 -30
- package/dist/channels/slack/scaffold/slack-send.ts +8 -8
- package/dist/channels/slack/scaffold/slack-threads.ts +4 -4
- package/dist/channels/slack/setup.d.ts +7 -0
- package/dist/channels/slack/setup.js +119 -0
- package/dist/channels/slack/slack-api.d.ts +2 -0
- package/dist/channels/slack/slack-api.js +4 -0
- package/dist/channels/slack/slack.d.ts +21 -2
- package/dist/channels/slack/slack.js +398 -338
- package/dist/channels/slack/socket.d.ts +57 -0
- package/dist/channels/slack/socket.js +305 -0
- package/dist/channels/telegram/polling.d.ts +27 -0
- package/dist/channels/telegram/polling.js +105 -0
- package/dist/channels/telegram/scaffold/channel.ts +52 -32
- package/dist/channels/telegram/scaffold/telegram-send.ts +9 -9
- package/dist/channels/telegram/setup.d.ts +2 -0
- package/dist/channels/telegram/setup.js +42 -0
- package/dist/channels/telegram/telegram-api.d.ts +27 -1
- package/dist/channels/telegram/telegram-api.js +7 -6
- package/dist/channels/telegram/telegram.d.ts +11 -3
- package/dist/channels/telegram/telegram.js +184 -157
- package/dist/channels/webhook-evidence.d.ts +11 -0
- package/dist/channels/webhook-evidence.js +71 -0
- package/dist/channels/webhooks.d.ts +37 -0
- package/dist/channels/webhooks.js +70 -0
- package/dist/child-env.d.ts +16 -0
- package/dist/child-env.js +30 -0
- package/dist/cli/box-login.js +4 -1
- package/dist/cli/channel-app.d.ts +3 -0
- package/dist/cli/channel-app.js +35 -0
- package/dist/cli/channel-setup.d.ts +38 -0
- package/dist/cli/channel-setup.js +195 -0
- package/dist/cli/commands/add.d.ts +6 -14
- package/dist/cli/commands/add.js +45 -303
- package/dist/cli/commands/auth.js +8 -2
- package/dist/cli/commands/build.d.ts +5 -0
- package/dist/cli/commands/build.js +16 -0
- package/dist/cli/commands/channels.d.ts +19 -0
- package/dist/cli/commands/channels.js +230 -0
- package/dist/cli/commands/content.d.ts +7 -3
- package/dist/cli/commands/content.js +16 -10
- package/dist/cli/commands/deploy/agentcore.js +55 -23
- package/dist/cli/commands/deploy/channel-apps.d.ts +17 -0
- package/dist/cli/commands/deploy/channel-apps.js +30 -0
- package/dist/cli/commands/deploy/docker.js +32 -65
- package/dist/cli/commands/deploy/fly.js +28 -12
- package/dist/cli/commands/deploy/railway.js +38 -13
- package/dist/cli/commands/deploy/secrets-step.d.ts +19 -0
- package/dist/cli/commands/deploy/secrets-step.js +66 -0
- package/dist/cli/commands/deploy/shared.d.ts +16 -5
- package/dist/cli/commands/deploy/shared.js +25 -8
- package/dist/cli/commands/deploy.js +53 -60
- package/dist/cli/commands/dev.d.ts +2 -0
- package/dist/cli/commands/dev.js +15 -3
- package/dist/cli/commands/env.js +1 -1
- package/dist/cli/commands/info.d.ts +2 -0
- package/dist/cli/commands/info.js +60 -25
- package/dist/cli/commands/init.js +3 -1
- package/dist/cli/commands/invoke.d.ts +2 -0
- package/dist/cli/commands/invoke.js +20 -7
- package/dist/cli/commands/login.d.ts +0 -7
- package/dist/cli/commands/login.js +22 -10
- package/dist/cli/commands/logout.js +1 -1
- package/dist/cli/commands/mcp.js +14 -6
- package/dist/cli/commands/models.js +3 -2
- package/dist/cli/commands/schedules.d.ts +4 -2
- package/dist/cli/commands/schedules.js +14 -10
- package/dist/cli/commands/secrets.d.ts +14 -0
- package/dist/cli/commands/secrets.js +213 -0
- package/dist/cli/commands/start.d.ts +14 -14
- package/dist/cli/commands/start.js +46 -60
- package/dist/cli/content-view.d.ts +4 -6
- package/dist/cli/content-view.js +5 -11
- package/dist/cli/first-run-channels.d.ts +3 -0
- package/dist/cli/first-run-channels.js +63 -0
- package/dist/cli/instance.d.ts +41 -0
- package/dist/cli/instance.js +155 -0
- package/dist/cli/invoke-stream.d.ts +5 -2
- package/dist/cli/invoke-stream.js +7 -2
- package/dist/cli/kernel.js +3 -0
- package/dist/cli/program.js +282 -110
- package/dist/cli/serve.d.ts +4 -5
- package/dist/cli/serve.js +4 -7
- package/dist/cli/shared.d.ts +11 -2
- package/dist/cli/shared.js +32 -19
- package/dist/cli/ticket.d.ts +7 -0
- package/dist/cli/ticket.js +106 -30
- package/dist/content/declare.d.ts +31 -37
- package/dist/content/declare.js +59 -60
- package/dist/content/file.d.ts +23 -12
- package/dist/content/file.js +48 -35
- package/dist/content/git.d.ts +0 -10
- package/dist/content/git.js +5 -39
- package/dist/content/resolve.d.ts +18 -22
- package/dist/content/resolve.js +32 -66
- package/dist/content/source.d.ts +7 -8
- package/dist/content/source.js +10 -28
- package/dist/credentials-page.d.ts +26 -0
- package/dist/credentials-page.js +185 -0
- package/dist/declared-secrets.d.ts +10 -3
- package/dist/declared-secrets.js +8 -4
- package/dist/deploy/agentcore/destroy.d.ts +4 -1
- package/dist/deploy/agentcore/destroy.js +25 -1
- package/dist/deploy/agentcore/forwarder.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +7 -21
- package/dist/deploy/agentcore/plan.js +47 -49
- package/dist/deploy/agentcore/run.d.ts +18 -10
- package/dist/deploy/agentcore/run.js +93 -70
- package/dist/deploy/agentcore/runtime-secrets.d.ts +7 -0
- package/dist/deploy/agentcore/runtime-secrets.js +108 -0
- package/dist/deploy/agentcore/shell.js +12 -19
- package/dist/deploy/agentcore/sigv4.d.ts +7 -0
- package/dist/deploy/agentcore/sigv4.js +15 -0
- package/dist/deploy/agentcore/slr.d.ts +18 -0
- package/dist/deploy/agentcore/slr.js +27 -0
- package/dist/deploy/agentcore/store.d.ts +7 -0
- package/dist/deploy/agentcore/store.js +115 -0
- package/dist/deploy/api.d.ts +14 -14
- package/dist/deploy/api.js +26 -24
- package/dist/deploy/box-shell.d.ts +3 -1
- package/dist/deploy/build-context.d.ts +4 -4
- package/dist/deploy/build-context.js +11 -15
- package/dist/deploy/channel-ingress.d.ts +35 -9
- package/dist/deploy/channel-ingress.js +119 -22
- package/dist/deploy/container.d.ts +35 -10
- package/dist/deploy/container.js +79 -37
- package/dist/deploy/delivered-text.d.ts +13 -0
- package/dist/deploy/delivered-text.js +86 -0
- package/dist/deploy/docker/plan.d.ts +7 -8
- package/dist/deploy/docker/plan.js +31 -52
- package/dist/deploy/docker/run.d.ts +5 -43
- package/dist/deploy/docker/run.js +9 -84
- package/dist/deploy/file-store.d.ts +2 -0
- package/dist/deploy/file-store.js +17 -0
- package/dist/deploy/fly/plan.d.ts +3 -2
- package/dist/deploy/fly/plan.js +20 -9
- package/dist/deploy/fly/run.d.ts +18 -8
- package/dist/deploy/fly/run.js +24 -42
- package/dist/deploy/fly/store.d.ts +12 -0
- package/dist/deploy/fly/store.js +83 -0
- package/dist/deploy/hosts.d.ts +1 -2
- package/dist/deploy/hosts.js +1 -2
- package/dist/deploy/preflight.d.ts +18 -5
- package/dist/deploy/preflight.js +135 -63
- package/dist/deploy/railway/ignore.d.ts +8 -0
- package/dist/deploy/railway/ignore.js +57 -0
- package/dist/deploy/railway/plan.d.ts +1 -2
- package/dist/deploy/railway/plan.js +8 -6
- package/dist/deploy/railway/run.d.ts +21 -15
- package/dist/deploy/railway/run.js +32 -78
- package/dist/deploy/railway/store.d.ts +29 -0
- package/dist/deploy/railway/store.js +143 -0
- package/dist/deploy/runner.d.ts +5 -2
- package/dist/deploy/runner.js +4 -3
- package/dist/deploy/secret-store.d.ts +63 -0
- package/dist/deploy/secret-store.js +98 -0
- package/dist/deploy/secrets.d.ts +29 -46
- package/dist/deploy/secrets.js +49 -122
- package/dist/deploy/workspace.d.ts +6 -12
- package/dist/deploy/workspace.js +18 -94
- package/dist/dev-supervisor.js +6 -8
- package/dist/environment/declare.js +3 -2
- package/dist/environment/mise.d.ts +3 -1
- package/dist/environment/mise.js +4 -2
- package/dist/feishu.d.ts +1 -1
- package/dist/feishu.js +1 -1
- package/dist/harnesses/models/catalog.d.ts +1 -0
- package/dist/harnesses/models/catalog.js +1 -2
- package/dist/harnesses/models/environment.d.ts +7 -2
- package/dist/harnesses/models/environment.js +9 -5
- package/dist/harnesses/models/host.d.ts +0 -7
- package/dist/harnesses/models/host.js +10 -1
- package/dist/harnesses/models/login.d.ts +0 -8
- package/dist/harnesses/models/login.js +5 -4
- package/dist/harnesses/models/models.d.ts +7 -2
- package/dist/harnesses/models/models.js +28 -4
- package/dist/harnesses/pi-durable/agent.js +59 -38
- package/dist/harnesses/pi-durable/build.d.ts +12 -0
- package/dist/harnesses/pi-durable/build.js +270 -0
- package/dist/harnesses/pi-durable/built.d.ts +24 -0
- package/dist/harnesses/pi-durable/built.js +136 -0
- package/dist/harnesses/pi-durable/config.d.ts +81 -0
- package/dist/harnesses/pi-durable/config.js +266 -0
- package/dist/harnesses/pi-durable/define.d.ts +63 -13
- package/dist/harnesses/pi-durable/define.js +23 -2
- package/dist/harnesses/pi-durable/definition.d.ts +72 -0
- package/dist/harnesses/pi-durable/definition.js +143 -0
- package/dist/harnesses/pi-durable/events.d.ts +4 -3
- package/dist/harnesses/pi-durable/events.js +179 -136
- package/dist/harnesses/pi-durable/execution-env.d.ts +17 -0
- package/dist/harnesses/pi-durable/execution-env.js +11 -0
- package/dist/harnesses/pi-durable/mcp.js +1 -3
- package/dist/harnesses/pi-durable/open.d.ts +35 -37
- package/dist/harnesses/pi-durable/open.js +91 -153
- package/dist/harnesses/pi-durable/reads.d.ts +0 -1
- package/dist/harnesses/pi-durable/reads.js +1 -3
- package/dist/harnesses/pi-durable/registry.d.ts +4 -6
- package/dist/harnesses/pi-durable/registry.js +29 -26
- package/dist/harnesses/pi-durable/release.d.ts +2 -2
- package/dist/harnesses/pi-durable/release.js +10 -7
- package/dist/harnesses/pi-durable/serve.d.ts +91 -15
- package/dist/harnesses/pi-durable/serve.js +109 -47
- package/dist/harnesses/pi-durable/sessions.js +15 -12
- package/dist/harnesses/pi-durable/text-sources.d.ts +30 -0
- package/dist/harnesses/pi-durable/text-sources.js +55 -0
- package/dist/harnesses/pi-durable/text.d.ts +16 -4
- package/dist/harnesses/pi-durable/text.js +115 -59
- package/dist/harnesses/pi-durable/wake.js +8 -8
- package/dist/http/client.js +9 -3
- package/dist/http/contract.d.ts +3 -3
- package/dist/http/server.d.ts +1 -1
- package/dist/http/server.js +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +4 -1
- package/dist/instance-name.d.ts +7 -0
- package/dist/instance-name.js +26 -0
- package/dist/lark.d.ts +1 -1
- package/dist/lark.js +1 -1
- package/dist/mcp/client.js +11 -2
- package/dist/mcp/config.d.ts +70 -18
- package/dist/mcp/config.js +136 -53
- package/dist/mcp/host.d.ts +5 -2
- package/dist/mcp/host.js +14 -6
- package/dist/mcp/sign-in.js +2 -2
- package/dist/mcp-api.d.ts +14 -0
- package/dist/paths.d.ts +22 -8
- package/dist/paths.js +44 -11
- package/dist/runtime-websocket.d.ts +14 -0
- package/dist/runtime-websocket.js +39 -0
- package/dist/scaffold/add-channel.d.ts +9 -16
- package/dist/scaffold/add-channel.js +13 -83
- package/dist/scaffold/templates/env.example +4 -5
- package/dist/scaffold/templates/fastagent.config.ts +20 -14
- package/dist/scaffold/templates/gitignore +9 -6
- package/dist/scaffold/templates.d.ts +6 -2
- package/dist/scaffold/templates.js +7 -2
- package/dist/scaffold/vendor-skill.js +4 -2
- package/dist/service.d.ts +44 -6
- package/dist/service.js +110 -10
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +1 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/strip-edges.d.ts +10 -0
- package/dist/strip-edges.js +22 -0
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +1 -1
- package/dist/tunnel.d.ts +0 -1
- package/dist/tunnel.js +2 -8
- package/dist/value-file.d.ts +11 -6
- package/dist/value-file.js +21 -9
- package/dist/version.d.ts +7 -1
- package/dist/version.js +9 -3
- package/package.json +6 -5
- package/dist/channels/lark/credentials-page.d.ts +0 -25
- package/dist/channels/lark/credentials-page.js +0 -206
- package/dist/channels/lark/onboard.d.ts +0 -52
- package/dist/channels/lark/onboard.js +0 -86
- package/dist/channels/slack/config-api.d.ts +0 -69
- package/dist/channels/slack/config-api.js +0 -162
- package/dist/channels/slack/onboard.d.ts +0 -40
- package/dist/channels/slack/onboard.js +0 -136
- package/dist/channels/slack/onboarding-state.d.ts +0 -31
- package/dist/channels/slack/onboarding-state.js +0 -64
- package/dist/channels/slack/register-webhook.d.ts +0 -12
- package/dist/channels/slack/register-webhook.js +0 -67
- package/dist/channels/slack/setup-server.d.ts +0 -32
- package/dist/channels/slack/setup-server.js +0 -246
- package/dist/cli/add-feishu.d.ts +0 -41
- package/dist/cli/add-feishu.js +0 -391
- package/dist/cli/add-slack.d.ts +0 -18
- package/dist/cli/add-slack.js +0 -216
- package/dist/harnesses/pi-durable/parked.d.ts +0 -18
- package/dist/harnesses/pi-durable/parked.js +0 -27
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromForwarder } from "./agentcore-protocol.js";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
|
-
import { routesFor, serviceOver, startSchedules, } from "../service.js";
|
|
3
|
+
import { routesFor, serviceOver, startSchedules, webhooksOf, } from "../service.js";
|
|
4
4
|
import { agentcoreRoutes, agentcorePing } from "./agentcore.js";
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import { fireScheduleOnce } from "../schedule/scheduler.js";
|
|
@@ -99,9 +99,10 @@ export async function mountAgentcoreService(opened) {
|
|
|
99
99
|
// recurring schedule the container sets (`armAlarms`), ONE path per instant, so the reply to that delivery says
|
|
100
100
|
// whether it ran. The clock still pumps wake-ups; a redelivered fire claims its slot once.
|
|
101
101
|
const mirror = armAlarms(stateRoot, () => schedules);
|
|
102
|
+
const webhooks = webhooksOf(opened);
|
|
102
103
|
const scheduled = startSchedules(agent, stateRoot, schedules, { localClock: false });
|
|
103
104
|
const lazyChannels = async () => {
|
|
104
|
-
const lazy = routesFor(agent, stateRoot, opened.channels);
|
|
105
|
+
const lazy = routesFor(agent, stateRoot, opened.channels, webhooks.list);
|
|
105
106
|
if (lazy.longConnections.length > 0) {
|
|
106
107
|
throw new Error(`long-connection channel(s) ${lazy.longConnections.map((c) => c.name).join(", ")} cannot serve on ` +
|
|
107
108
|
`AgentCore (scale-to-zero severs resident connections) — use the channel's webhook form`);
|
|
@@ -113,13 +114,21 @@ export async function mountAgentcoreService(opened) {
|
|
|
113
114
|
stateRoot,
|
|
114
115
|
schedules: () => schedules,
|
|
115
116
|
...(mirror ? { onStateReady: mirror } : {}),
|
|
117
|
+
webhooks: {
|
|
118
|
+
list: webhooks.list,
|
|
119
|
+
// A custom domain the operator named in the configuration is where the platforms reach it, not the Function URL.
|
|
120
|
+
point: (forwarderUrl) => webhooks.register(opened.config.http?.publicUrl ?? forwarderUrl),
|
|
121
|
+
},
|
|
116
122
|
channels: lazyChannels,
|
|
117
123
|
});
|
|
118
124
|
const handler = router(adapterRoutes);
|
|
119
125
|
log.info(`[fastagent] agentcore: serving POST /invocations + GET /ping (FASTAGENT_AGENTCORE=1)`);
|
|
120
126
|
return {
|
|
121
127
|
// Nothing to open: no port of its own, no resident connections.
|
|
122
|
-
...serviceOver(handler, Promise.resolve(), async () =>
|
|
128
|
+
...serviceOver(handler, Promise.resolve(), async () => {
|
|
129
|
+
webhooks.dispose();
|
|
130
|
+
await scheduled.stop();
|
|
131
|
+
}),
|
|
123
132
|
// The adapter IS the surface here; the channel routes arrive lazily BEHIND it.
|
|
124
133
|
routes: adapterRoutes,
|
|
125
134
|
agentDir,
|
|
@@ -135,7 +144,7 @@ export async function mountAgentcoreService(opened) {
|
|
|
135
144
|
* surface (channels/agentcore.ts).
|
|
136
145
|
*/
|
|
137
146
|
export function mountAgentcore(options) {
|
|
138
|
-
const { agent, stateRoot, schedules, onStateReady, channels } = options;
|
|
147
|
+
const { agent, stateRoot, schedules, onStateReady, channels, webhooks } = options;
|
|
139
148
|
// OCCURRENCE SEMANTICS, because this host's clock is ours: the container set the recurring schedule that names this
|
|
140
149
|
// instant and the forwarder relays it behind the ingress secret, so a claim means something (dedup across
|
|
141
150
|
// EventBridge's redeliveries, a fire history, the overlap policy).
|
|
@@ -172,6 +181,7 @@ export function mountAgentcore(options) {
|
|
|
172
181
|
ingressSecret: process.env.FASTAGENT_INGRESS_SECRET,
|
|
173
182
|
onStateReady,
|
|
174
183
|
fireSchedule,
|
|
184
|
+
...(webhooks ? { webhooks } : {}),
|
|
175
185
|
});
|
|
176
186
|
}
|
|
177
187
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ChannelHandler, Routes } from "../channel.ts";
|
|
2
|
+
import type { WebhookRegistration } from "./webhooks.ts";
|
|
2
3
|
/**
|
|
3
4
|
* What the lazy factory hands back: the CHANNELS' routes, and nothing else.
|
|
4
5
|
*
|
|
@@ -33,6 +34,14 @@ export interface AgentcoreAdapterOptions {
|
|
|
33
34
|
ingressSecret?: string;
|
|
34
35
|
/** Runs once on activation, after accepting the current forwarder callback URL. */
|
|
35
36
|
onStateReady?: () => void;
|
|
37
|
+
/**
|
|
38
|
+
* The webhook channels this container points at the forwarder: `point` is called once, on the first trusted
|
|
39
|
+
* envelope that constructed the channels, with the URL that envelope names; `list` is what a probe reports.
|
|
40
|
+
*/
|
|
41
|
+
webhooks?: {
|
|
42
|
+
point(forwarderUrl: string): Promise<unknown>;
|
|
43
|
+
list(): readonly WebhookRegistration[];
|
|
44
|
+
};
|
|
36
45
|
}
|
|
37
46
|
export declare function agentcoreRoutes(options: AgentcoreAdapterOptions): Routes;
|
|
38
47
|
export declare function agentcorePing(isBusy: () => boolean): ChannelHandler;
|
|
@@ -41,8 +41,28 @@ function createActivation(deps) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
export function agentcoreRoutes(options) {
|
|
44
|
-
const { channels, stateRoot, isBusy, fireSchedule, ingressSecret, onStateReady } = options;
|
|
44
|
+
const { channels, stateRoot, isBusy, fireSchedule, ingressSecret, onStateReady, webhooks } = options;
|
|
45
45
|
const activation = createActivation({ stateRoot, onStateReady, channels });
|
|
46
|
+
// Under the process's busy signal: AgentCore reclaims a microVM with nothing in flight, and a registration is a
|
|
47
|
+
// call to the platform that must end.
|
|
48
|
+
let pointed = false;
|
|
49
|
+
const pointWebhooks = (url) => {
|
|
50
|
+
if (webhooks === undefined || pointed)
|
|
51
|
+
return;
|
|
52
|
+
pointed = true;
|
|
53
|
+
void (async () => {
|
|
54
|
+
const done = beginWork();
|
|
55
|
+
try {
|
|
56
|
+
await webhooks.point(url);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
log.error(`[agentcore] could not point the webhook channels at ${url}: ${String(error)}`);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
done();
|
|
63
|
+
}
|
|
64
|
+
})();
|
|
65
|
+
};
|
|
46
66
|
const carried = (request) => {
|
|
47
67
|
const { method, path, query, headers, bodyB64 } = request;
|
|
48
68
|
return new Request(`http://agentcore.local${path}${typeof query === "string" && query !== "" ? `?${query}` : ""}`, {
|
|
@@ -103,6 +123,8 @@ export function agentcoreRoutes(options) {
|
|
|
103
123
|
log.error(`[agentcore] channel construction failed: ${constructionError}`);
|
|
104
124
|
}
|
|
105
125
|
}
|
|
126
|
+
if (dispatch && typeof envelope.wake?.url === "string")
|
|
127
|
+
pointWebhooks(envelope.wake.url);
|
|
106
128
|
switch (envelope.kind) {
|
|
107
129
|
case "webhook": {
|
|
108
130
|
const { bodyB64 } = envelope;
|
|
@@ -160,9 +182,12 @@ export function agentcoreRoutes(options) {
|
|
|
160
182
|
case "probe": {
|
|
161
183
|
// The structured verdict (transport-200 — see the envelope doc). From the IAM door (untrusted) nothing was
|
|
162
184
|
// activated, so `ok` says only that the definition opened; channel construction is the forwarder probe's.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
185
|
+
if (constructionError !== undefined) {
|
|
186
|
+
return json({ ok: false, error: `channel construction failed: ${constructionError}` }, 200);
|
|
187
|
+
}
|
|
188
|
+
return json(trusted
|
|
189
|
+
? { ok: true, webhooks: (webhooks?.list() ?? []).map((w) => ({ channel: w.channel, outcome: w.outcome })) }
|
|
190
|
+
: { ok: true }, 200);
|
|
166
191
|
}
|
|
167
192
|
default:
|
|
168
193
|
return text(`unknown envelope kind "${envelope.kind}"\n`, 400);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Agent } from "../agent-api.ts";
|
|
2
2
|
import type { ChannelContext } from "../channel.ts";
|
|
3
|
+
/** The directory of the channel `name`'s own state under `stateRoot`: its context's `stateDir`. */
|
|
4
|
+
export declare function channelStateDir(stateRoot: string, name: string): string;
|
|
3
5
|
/** The context of the channel `name` (its file's name under `src/channels/`), its state under `stateRoot`. */
|
|
4
6
|
export declare function channelContext(agent: Agent, stateRoot: string, name: string): ChannelContext;
|
package/dist/channels/context.js
CHANGED
|
@@ -10,11 +10,15 @@ import { portError, portJoin } from "../effect-port.js";
|
|
|
10
10
|
import { log } from "../log.js";
|
|
11
11
|
import { ensureStateHome } from "../state-file.js";
|
|
12
12
|
import { createTurnQueue } from "./turn-queue.js";
|
|
13
|
+
/** The directory of the channel `name`'s own state under `stateRoot`: its context's `stateDir`. */
|
|
14
|
+
export function channelStateDir(stateRoot, name) {
|
|
15
|
+
return join(stateRoot, "channels", name);
|
|
16
|
+
}
|
|
13
17
|
/** The context of the channel `name` (its file's name under `src/channels/`), its state under `stateRoot`. */
|
|
14
18
|
export function channelContext(agent, stateRoot, name) {
|
|
15
19
|
if (!isAbsolute(stateRoot))
|
|
16
20
|
throw new Error(`a channel's state root must be absolute, got "${stateRoot}"`);
|
|
17
|
-
const stateDir =
|
|
21
|
+
const stateDir = channelStateDir(stateRoot, name);
|
|
18
22
|
ensureStateHome(stateDir);
|
|
19
23
|
const sessions = conversationSessions(join(stateDir, "sessions.json"));
|
|
20
24
|
const turns = createTurnQueue({
|
|
@@ -61,7 +61,7 @@ export interface FeishuListedMessage {
|
|
|
61
61
|
sender_type?: string;
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
interface FeishuAppScope {
|
|
65
65
|
name: string;
|
|
66
66
|
grantStatus: number;
|
|
67
67
|
type?: "user" | "tenant";
|
|
@@ -177,3 +177,4 @@ export interface FeishuApi {
|
|
|
177
177
|
/** Split text into chunks whose UTF-8 size fits the message cap, preferring a newline boundary. */
|
|
178
178
|
export declare function chunkFeishuText(text: string, maxBytes?: number): string[];
|
|
179
179
|
export declare function createFeishuApi(opts: FeishuApiOptions): FeishuApi;
|
|
180
|
+
export {};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ChannelModule, LongConnectionChannelModule } from "../../channel.ts";
|
|
2
2
|
import { type FeishuCloudProfile } from "./cloud.ts";
|
|
3
|
-
import { type FeishuSubscriptionMode } from "./setup-mode.ts";
|
|
4
3
|
import { type FeishuMessage, type FeishuMessageEvent, type FeishuRoute, defaultFeishuRoute, feishuEnvelope } from "./parse.ts";
|
|
5
4
|
import { type FeishuFailure } from "./preview.ts";
|
|
6
5
|
import { connectFeishuWs } from "./ws-ingress.ts";
|
|
@@ -31,8 +30,6 @@ export type FeishuWebSocketChannelOptions = FeishuChannelBaseOptions & {
|
|
|
31
30
|
};
|
|
32
31
|
/** Build the canonical Feishu Request-URL webhook channel. */
|
|
33
32
|
export declare function feishuChannel(opts: FeishuChannelOptions): ChannelModule;
|
|
34
|
-
/** How this process receives the Feishu channel: `FEISHU_INGRESS`, else WebSocket under `dev` and webhook otherwise. */
|
|
35
|
-
export declare function feishuIngress(): FeishuSubscriptionMode;
|
|
36
33
|
/** Build the canonical Feishu WebSocket long-connection channel. */
|
|
37
34
|
export declare function feishuWebSocketChannel(opts: FeishuWebSocketChannelOptions): LongConnectionChannelModule;
|
|
38
35
|
/** Internal compatibility seams: protocol behavior comes from Feishu; the profile binds cloud edges. */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Canonical Feishu bot-channel engine: verified webhook or official-SDK WebSocket → dedup → route → persist → enqueue
|
|
3
3
|
* → stream a live card.
|
|
4
4
|
*/
|
|
5
|
+
import { recordReached } from "../webhook-evidence.js";
|
|
5
6
|
import { join } from "node:path";
|
|
6
7
|
import { Effect } from "effect";
|
|
7
8
|
import { log } from "../../log.js";
|
|
@@ -27,7 +28,7 @@ import { feishuTurnStream } from "./invoke-turn.js";
|
|
|
27
28
|
import { createFeishuApi } from "./feishu-api.js";
|
|
28
29
|
import { normalizeFeishuMessage } from "./normalize.js";
|
|
29
30
|
import { createThreadParticipants } from "../kit/thread-participants.js";
|
|
30
|
-
import { FEISHU_AGENT_SCOPES,
|
|
31
|
+
import { FEISHU_AGENT_SCOPES, scopeSatisfied } from "./setup-mode.js";
|
|
31
32
|
import { cloudEnvelope, defaultFeishuRoute, feishuEnvelope, placeKey, senderId, } from "./parse.js";
|
|
32
33
|
import { defaultErrorMessage, mountFeishuPreview, settleFeishuPreview, feishuReply, } from "./preview.js";
|
|
33
34
|
import { connectFeishuWs } from "./ws-ingress.js";
|
|
@@ -75,10 +76,6 @@ function isStoredFeishuTurn(t) {
|
|
|
75
76
|
export function feishuChannel(opts) {
|
|
76
77
|
return buildFeishuChannel(FEISHU_CLOUD, opts, feishuChannel.name);
|
|
77
78
|
}
|
|
78
|
-
/** How this process receives the Feishu channel: `FEISHU_INGRESS`, else WebSocket under `dev` and webhook otherwise. */
|
|
79
|
-
export function feishuIngress() {
|
|
80
|
-
return feishuIngressFor("feishu");
|
|
81
|
-
}
|
|
82
79
|
/** Build the canonical Feishu WebSocket long-connection channel. */
|
|
83
80
|
export function feishuWebSocketChannel(opts) {
|
|
84
81
|
return buildFeishuWebSocketChannel(FEISHU_CLOUD, opts, feishuWebSocketChannel.name);
|
|
@@ -418,7 +415,7 @@ function createFeishuRuntimeFactory(profile, opts, factoryName) {
|
|
|
418
415
|
return { acceptEvent, turnsIdle: () => Promise.all([runner.idle(), sideTasks.drain()]).then(() => undefined) };
|
|
419
416
|
};
|
|
420
417
|
}
|
|
421
|
-
function createFeishuWebhookRoutes(profile, opts, runtime) {
|
|
418
|
+
function createFeishuWebhookRoutes(profile, opts, runtime, stateDir) {
|
|
422
419
|
const { verificationToken, encryptKey } = opts;
|
|
423
420
|
const { kind, envPrefix } = profile;
|
|
424
421
|
const label = `[${kind}]`;
|
|
@@ -496,6 +493,9 @@ function createFeishuWebhookRoutes(profile, opts, runtime) {
|
|
|
496
493
|
log.warn(`${label} rejected an event: verification token mismatch (check ${envPrefix}_VERIFICATION_TOKEN against the console)`);
|
|
497
494
|
return text("invalid token\n", 401);
|
|
498
495
|
}
|
|
496
|
+
// The platform's token: the Request URL reaches this instance, at the address it was sent to (Lark's, set by a
|
|
497
|
+
// person where its configuration API is missing).
|
|
498
|
+
recordReached(stateDir, req);
|
|
499
499
|
if (envelope.type === "url_verification" && typeof envelope.challenge === "string") {
|
|
500
500
|
log.info(`${label} answered the console's url_verification challenge`);
|
|
501
501
|
return Response.json({ challenge: envelope.challenge });
|
|
@@ -517,11 +517,11 @@ export function buildFeishuChannel(profile, opts, factoryName) {
|
|
|
517
517
|
if (!opts.verificationToken) {
|
|
518
518
|
// The scaffolded file reaches this under `start` with nothing set, so the error names both ways out.
|
|
519
519
|
throw new Error(`${factoryName} receives by webhook and needs a non-empty verificationToken: \`fastagent deploy <host> --run\` ` +
|
|
520
|
-
`or \`fastagent
|
|
521
|
-
`(console → Events & Callbacks has it too), or set
|
|
522
|
-
`WebSocket instead`);
|
|
520
|
+
`or \`fastagent channels setup ${profile.kind} --ingress webhook\` captures ${profile.envPrefix}_VERIFICATION_TOKEN ` +
|
|
521
|
+
`(console → Events & Callbacks has it too), or set channels.<name>.ingress to "connection" in the instance's ` +
|
|
522
|
+
`fastagent.json to receive by WebSocket instead`);
|
|
523
523
|
}
|
|
524
|
-
return createFeishuWebhookRoutes(profile, opts, createRuntime(ctx));
|
|
524
|
+
return createFeishuWebhookRoutes(profile, opts, createRuntime(ctx), ctx.stateDir);
|
|
525
525
|
};
|
|
526
526
|
}
|
|
527
527
|
export function buildFeishuWebSocketChannel(profile, opts, factoryName, deps = {}) {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* it behind something non-trivial, adopt the official SDK rather than chasing it.
|
|
7
7
|
*/
|
|
8
8
|
import { gzipSync } from "node:zlib";
|
|
9
|
+
import { stripEnd } from "../../strip-edges.js";
|
|
9
10
|
/** Feishu accounts endpoint (the flow starts here for every user; a Lark-tenant scan switches over). */
|
|
10
11
|
const FEISHU_ACCOUNTS = "https://accounts.feishu.cn";
|
|
11
12
|
const LARK_ACCOUNTS = "https://accounts.larksuite.com";
|
|
@@ -14,11 +15,8 @@ const ENDPOINT = "/oauth/v1/app/registration";
|
|
|
14
15
|
const REQUEST_TIMEOUT_MS = 30_000;
|
|
15
16
|
/** JSON → gzip → base64url — the platform's fixed addons encoding. */
|
|
16
17
|
export function encodeAddons(addons) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.replace(/\+/g, "-")
|
|
20
|
-
.replace(/\//g, "_")
|
|
21
|
-
.replace(/=+$/, "");
|
|
18
|
+
const base64 = gzipSync(Buffer.from(JSON.stringify(addons), "utf8")).toString("base64");
|
|
19
|
+
return stripEnd(base64.replace(/\+/g, "-").replace(/\//g, "_"), (char) => char === "=");
|
|
22
20
|
}
|
|
23
21
|
/** RFC 8628 device-flow states whose non-2xx JSON bodies belong to the polling state machine. */
|
|
24
22
|
const DEVICE_FLOW_ERRORS = new Set(["authorization_pending", "slow_down", "access_denied", "expired_token"]);
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import { needs } from "@fastagent-sh/fastagent";
|
|
2
|
-
import {
|
|
3
|
-
type FeishuChannelOptions,
|
|
4
|
-
feishuChannel,
|
|
5
|
-
feishuIngress,
|
|
6
|
-
feishuWebSocketChannel,
|
|
7
|
-
} from "@fastagent-sh/fastagent/feishu";
|
|
1
|
+
import { byIngress, needs } from "@fastagent-sh/fastagent";
|
|
2
|
+
import { type FeishuChannelOptions, feishuChannel, feishuWebSocketChannel } from "@fastagent-sh/fastagent/feishu";
|
|
8
3
|
|
|
9
4
|
// fastagent's canonical Feishu adapter (verify + run + reply), configured with YOUR policy. Feishu
|
|
10
5
|
// (open.feishu.cn) only; a Lark-international tenant uses `fastagent add lark` instead.
|
|
11
6
|
//
|
|
12
|
-
// How it receives is
|
|
13
|
-
//
|
|
14
|
-
// receives by webhook at POST /feishu
|
|
15
|
-
//
|
|
7
|
+
// How it receives is the instance's choice, `channels.feishu.ingress` in its fastagent.json (webhook |
|
|
8
|
+
// connection). Unset, `fastagent dev` opens a long connection OUT (no public URL, no tunnel), and everything
|
|
9
|
+
// else — `fastagent start`, every deployment — receives by webhook at POST /feishu, the way a host that
|
|
10
|
+
// wakes on a request is reached.
|
|
11
|
+
// Dev reads .secrets/.env; production reads .secrets/production/.env. Interactive `deploy --run`
|
|
12
|
+
// creates a separate production app.
|
|
16
13
|
//
|
|
17
|
-
// `fastagent
|
|
14
|
+
// `fastagent channels setup feishu` creates and configures the app (scan-to-create). For a hand-made app, in the
|
|
18
15
|
// developer console:
|
|
19
16
|
// 1. create a custom app → enable the BOT capability → copy App ID / App Secret into .env
|
|
20
17
|
// 2. Permissions: add `im:message.p2p_msg:readonly` (direct messages), `im:message.group_at_msg:readonly`
|
|
@@ -45,25 +42,26 @@ const policy: Pick<FeishuChannelOptions, "onError" | "route"> = {
|
|
|
45
42
|
// route: (e) => defaultFeishuRoute(e, { botOpenId: "ou_xxx" }) && { text: `${feishuEnvelope(e)}\n[extra]` },
|
|
46
43
|
};
|
|
47
44
|
|
|
48
|
-
// `needs` declares the env vars
|
|
49
|
-
//
|
|
50
|
-
export default
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
: needs(["FEISHU_APP_ID", "FEISHU_APP_SECRET"], (secrets) =>
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
// Each way's `needs` declares the env vars it reads: an instance is asked only for its way's, and
|
|
46
|
+
// refused to serve while a required one is unset. FEISHU_ENCRYPT_KEY is optional.
|
|
47
|
+
export default byIngress({
|
|
48
|
+
webhook: needs(
|
|
49
|
+
[
|
|
50
|
+
"FEISHU_APP_ID",
|
|
51
|
+
"FEISHU_APP_SECRET",
|
|
52
|
+
"FEISHU_VERIFICATION_TOKEN",
|
|
53
|
+
{ name: "FEISHU_ENCRYPT_KEY", description: "when set, plaintext events are refused", optional: true },
|
|
54
|
+
],
|
|
55
|
+
(secrets) =>
|
|
56
|
+
feishuChannel({
|
|
57
|
+
appId: secrets.FEISHU_APP_ID,
|
|
58
|
+
appSecret: secrets.FEISHU_APP_SECRET,
|
|
59
|
+
verificationToken: secrets.FEISHU_VERIFICATION_TOKEN, // authenticates inbound events
|
|
60
|
+
encryptKey: secrets.FEISHU_ENCRYPT_KEY,
|
|
61
|
+
...policy,
|
|
62
|
+
}),
|
|
63
|
+
),
|
|
64
|
+
connection: needs(["FEISHU_APP_ID", "FEISHU_APP_SECRET"], (secrets) =>
|
|
65
|
+
feishuWebSocketChannel({ appId: secrets.FEISHU_APP_ID, appSecret: secrets.FEISHU_APP_SECRET, ...policy }),
|
|
66
|
+
),
|
|
67
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { obj, opt, str } from "@earendil-works/pi-schema";
|
|
2
2
|
import { defineTool } from "@earendil-works/pi-durable";
|
|
3
3
|
import { needs } from "@fastagent-sh/fastagent";
|
|
4
4
|
import { feishuTransport } from "@fastagent-sh/fastagent/feishu";
|
|
@@ -18,10 +18,10 @@ export default needs(["FEISHU_APP_ID", "FEISHU_APP_SECRET"], (secrets) =>
|
|
|
18
18
|
"or memory); the [feishu: chat …] context line only identifies the chat you are answering, the " +
|
|
19
19
|
"one chat this tool must not target in a chat turn. Pass exactly ONE of `text` (plain) or " +
|
|
20
20
|
"`markdown` (rendered as a card: headings, bold, code blocks, links).",
|
|
21
|
-
parameters:
|
|
22
|
-
chatId:
|
|
23
|
-
text:
|
|
24
|
-
markdown:
|
|
21
|
+
parameters: obj({
|
|
22
|
+
chatId: str({ description: "target chat id (oc_…)" }),
|
|
23
|
+
text: opt(str({ description: "plain text message to send" })),
|
|
24
|
+
markdown: opt(str({ description: "markdown to send as a card" })),
|
|
25
25
|
}),
|
|
26
26
|
execute: async ({ chatId, text, markdown }) => {
|
|
27
27
|
if ((text === undefined) === (markdown === undefined)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { obj, opt, str } from "@earendil-works/pi-schema";
|
|
2
2
|
import { defineTool } from "@earendil-works/pi-durable";
|
|
3
3
|
import { sessionIdOf } from "@fastagent-sh/fastagent";
|
|
4
4
|
import { feishuThreads } from "@fastagent-sh/fastagent/feishu";
|
|
@@ -14,8 +14,8 @@ export default defineTool({
|
|
|
14
14
|
"it when a question here concerns something discussed in a thread, such as whether a problem raised there was " +
|
|
15
15
|
"resolved: the answer is often what a person wrote in the thread. Only this chat's threads can be read, and " +
|
|
16
16
|
"only in a group chat turn.",
|
|
17
|
-
parameters:
|
|
18
|
-
threadId:
|
|
17
|
+
parameters: obj({
|
|
18
|
+
threadId: opt(str({ description: "a thread id from the list (omt_…); omit it to list" })),
|
|
19
19
|
}),
|
|
20
20
|
execute: async ({ threadId }, api, context) => {
|
|
21
21
|
const threads = feishuThreads(await sessionIdOf(api, context));
|
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import { type FeishuCloudKind } from "./cloud.ts";
|
|
2
1
|
/** Feishu/Lark app-level event subscription choice: how a channel receives, and what an app is set up for. */
|
|
3
|
-
export type FeishuSubscriptionMode = "webhook" | "
|
|
4
|
-
/** The settings {@link feishuIngressFor} reads, one per cloud: what `deploy` must read the way the box will. */
|
|
5
|
-
export declare const FEISHU_INGRESS_SETTINGS: string[];
|
|
6
|
-
/**
|
|
7
|
-
* How THIS process receives a Feishu/Lark channel (docs/design/channel-environments.md): `<PREFIX>_INGRESS` when the
|
|
8
|
-
* environment names one, else WebSocket under `dev` (no public URL, no reviewed scope) and webhook everywhere else,
|
|
9
|
-
* which is what every deployment runs. The channel file asks at import, and so does every reader of its shape: `deploy`
|
|
10
|
-
* inspects it in a process that is not `dev`, with the same value file loaded, so it sees what the box will serve.
|
|
11
|
-
*/
|
|
12
|
-
export declare function feishuIngressFor(kind: FeishuCloudKind, env?: NodeJS.ProcessEnv): FeishuSubscriptionMode;
|
|
2
|
+
export type FeishuSubscriptionMode = "webhook" | "connection";
|
|
13
3
|
/**
|
|
14
4
|
* Configuring THIS app through the v7 config API: registering a webhook Request URL and switching the subscription
|
|
15
5
|
* mode. Requested for a webhook app only. A tenant may review it, and a scope under review holds the app's whole first
|
|
@@ -46,7 +36,7 @@ export declare const FEISHU_AGENT_SCOPES: FeishuScopeRequest[];
|
|
|
46
36
|
export declare function feishuAppScopes(ingress: FeishuSubscriptionMode): FeishuScopeRequest[];
|
|
47
37
|
/**
|
|
48
38
|
* What a created app carries on top of the platform's agent template — the `addons` merged onto the confirm page. A
|
|
49
|
-
* scope that arrives here needs no console visit; one a tenant withholds is reported after creation (`
|
|
39
|
+
* scope that arrives here needs no console visit; one a tenant withholds is reported after creation (`setup.ts`).
|
|
50
40
|
*/
|
|
51
41
|
export declare function feishuAppAddons(ingress: FeishuSubscriptionMode): {
|
|
52
42
|
scopes: {
|
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
import { servedByDev } from "../../serving-command.js";
|
|
2
|
-
import { cloudFor } from "./cloud.js";
|
|
3
|
-
/** The settings {@link feishuIngressFor} reads, one per cloud: what `deploy` must read the way the box will. */
|
|
4
|
-
export const FEISHU_INGRESS_SETTINGS = ["feishu", "lark"].map((kind) => `${cloudFor(kind).envPrefix}_INGRESS`);
|
|
5
|
-
/**
|
|
6
|
-
* How THIS process receives a Feishu/Lark channel (docs/design/channel-environments.md): `<PREFIX>_INGRESS` when the
|
|
7
|
-
* environment names one, else WebSocket under `dev` (no public URL, no reviewed scope) and webhook everywhere else,
|
|
8
|
-
* which is what every deployment runs. The channel file asks at import, and so does every reader of its shape: `deploy`
|
|
9
|
-
* inspects it in a process that is not `dev`, with the same value file loaded, so it sees what the box will serve.
|
|
10
|
-
*/
|
|
11
|
-
export function feishuIngressFor(kind, env = process.env) {
|
|
12
|
-
const name = `${cloudFor(kind).envPrefix}_INGRESS`;
|
|
13
|
-
const raw = env[name]?.trim();
|
|
14
|
-
if (!raw)
|
|
15
|
-
return servedByDev(env) ? "websocket" : "webhook";
|
|
16
|
-
if (raw !== "webhook" && raw !== "websocket") {
|
|
17
|
-
throw new Error(`${name} must be "webhook" or "websocket", got "${raw}"`);
|
|
18
|
-
}
|
|
19
|
-
return raw;
|
|
20
|
-
}
|
|
21
1
|
/**
|
|
22
2
|
* Configuring THIS app through the v7 config API: registering a webhook Request URL and switching the subscription
|
|
23
3
|
* mode. Requested for a webhook app only. A tenant may review it, and a scope under review holds the app's whole first
|
|
@@ -57,7 +37,7 @@ export const FEISHU_AGENT_SCOPES = [
|
|
|
57
37
|
/** The config scope as an app needs it: webhook only ({@link FEISHU_APP_CONFIG_SCOPE}). */
|
|
58
38
|
const FEISHU_APP_CONFIG_REQUEST = {
|
|
59
39
|
request: FEISHU_APP_CONFIG_SCOPE,
|
|
60
|
-
withoutIt: "the Verification Token is not captured and no Request URL is registered for you (
|
|
40
|
+
withoutIt: "the Verification Token is not captured and no Request URL is registered for you (channels setup, dev --tunnel, deploy --run)",
|
|
61
41
|
};
|
|
62
42
|
/**
|
|
63
43
|
* Every scope an app of this ingress needs: what onboarding requests at creation AND what it checks the app holds, so a
|
|
@@ -68,7 +48,7 @@ export function feishuAppScopes(ingress) {
|
|
|
68
48
|
}
|
|
69
49
|
/**
|
|
70
50
|
* What a created app carries on top of the platform's agent template — the `addons` merged onto the confirm page. A
|
|
71
|
-
* scope that arrives here needs no console visit; one a tenant withholds is reported after creation (`
|
|
51
|
+
* scope that arrives here needs no console visit; one a tenant withholds is reported after creation (`setup.ts`).
|
|
72
52
|
*/
|
|
73
53
|
export function feishuAppAddons(ingress) {
|
|
74
54
|
return {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a Feishu or Lark app's setup asks for (channels/setup.ts). The two share one engine: the app's credentials come
|
|
3
|
+
* first (Feishu creates the app by scan-to-create and keeps what it returns; Lark's person creates it in its console and
|
|
4
|
+
* pastes them), then, for a webhook, the Verification Token, captured by a throwaway webhook registration when the app
|
|
5
|
+
* allows it and pasted when it does not. What is left to the person is the permission work and the publish, which
|
|
6
|
+
* depend on what the platform says about the app.
|
|
7
|
+
*/
|
|
8
|
+
import { type ChannelSetup, type SetupValue } from "../setup.ts";
|
|
9
|
+
import { type FeishuCloudKind } from "./cloud.ts";
|
|
10
|
+
/** The setup of a Feishu or Lark app whose credentials are `credentials`. */
|
|
11
|
+
export declare function feishuEngine(kind: FeishuCloudKind, credentials: SetupValue, context: Parameters<ChannelSetup>[0]): ReturnType<ChannelSetup>;
|
|
12
|
+
export declare const feishuSetup: ChannelSetup;
|