@dual-os/sdk 0.0.0-stage → 0.8.0-next.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 +4 -0
- package/README.md +19 -2
- package/dist/Action.d.ts +201 -0
- package/dist/Action.d.ts.map +1 -0
- package/dist/Action.js +172 -0
- package/dist/Action.js.map +1 -0
- package/dist/AgentChannel.d.ts +1717 -0
- package/dist/AgentChannel.d.ts.map +1 -0
- package/dist/AgentChannel.js +708 -0
- package/dist/AgentChannel.js.map +1 -0
- package/dist/AgentChannelConformance.d.ts +1543 -0
- package/dist/AgentChannelConformance.d.ts.map +1 -0
- package/dist/AgentChannelConformance.js +163 -0
- package/dist/AgentChannelConformance.js.map +1 -0
- package/dist/AgentChannelRuntime.d.ts +78 -0
- package/dist/AgentChannelRuntime.d.ts.map +1 -0
- package/dist/AgentChannelRuntime.js +270 -0
- package/dist/AgentChannelRuntime.js.map +1 -0
- package/dist/AiProvider.d.ts +132 -0
- package/dist/AiProvider.d.ts.map +1 -0
- package/dist/AiProvider.js +100 -0
- package/dist/AiProvider.js.map +1 -0
- package/dist/AuthMethod.d.ts +381 -0
- package/dist/AuthMethod.d.ts.map +1 -0
- package/dist/AuthMethod.js +225 -0
- package/dist/AuthMethod.js.map +1 -0
- package/dist/AuthMethodBinding.d.ts +77 -0
- package/dist/AuthMethodBinding.d.ts.map +1 -0
- package/dist/AuthMethodBinding.js +31 -0
- package/dist/AuthMethodBinding.js.map +1 -0
- package/dist/AuthMethodExecution.d.ts +223 -0
- package/dist/AuthMethodExecution.d.ts.map +1 -0
- package/dist/AuthMethodExecution.js +277 -0
- package/dist/AuthMethodExecution.js.map +1 -0
- package/dist/ConnectionResolver.d.ts +219 -0
- package/dist/ConnectionResolver.d.ts.map +1 -0
- package/dist/ConnectionResolver.js +153 -0
- package/dist/ConnectionResolver.js.map +1 -0
- package/dist/DefinitionError.d.ts +67 -0
- package/dist/DefinitionError.d.ts.map +1 -0
- package/dist/DefinitionError.js +82 -0
- package/dist/DefinitionError.js.map +1 -0
- package/dist/DualRegistry.d.ts +71 -0
- package/dist/DualRegistry.d.ts.map +1 -0
- package/dist/DualRegistry.js +96 -0
- package/dist/DualRegistry.js.map +1 -0
- package/dist/DualRuntime.d.ts +279 -0
- package/dist/DualRuntime.d.ts.map +1 -0
- package/dist/DualRuntime.js +311 -0
- package/dist/DualRuntime.js.map +1 -0
- package/dist/Files.d.ts +80 -0
- package/dist/Files.d.ts.map +1 -0
- package/dist/Files.js +66 -0
- package/dist/Files.js.map +1 -0
- package/dist/Group.d.ts +106 -0
- package/dist/Group.d.ts.map +1 -0
- package/dist/Group.js +86 -0
- package/dist/Group.js.map +1 -0
- package/dist/Http.d.ts +342 -0
- package/dist/Http.d.ts.map +1 -0
- package/dist/Http.js +677 -0
- package/dist/Http.js.map +1 -0
- package/dist/Mcp.d.ts +109 -0
- package/dist/Mcp.d.ts.map +1 -0
- package/dist/Mcp.js +176 -0
- package/dist/Mcp.js.map +1 -0
- package/dist/OAuth2TokenRefresher.d.ts +18 -0
- package/dist/OAuth2TokenRefresher.d.ts.map +1 -0
- package/dist/OAuth2TokenRefresher.js +19 -0
- package/dist/OAuth2TokenRefresher.js.map +1 -0
- package/dist/OAuthFlow.d.ts +71 -0
- package/dist/OAuthFlow.d.ts.map +1 -0
- package/dist/OAuthFlow.js +488 -0
- package/dist/OAuthFlow.js.map +1 -0
- package/dist/Plugin.d.ts +383 -0
- package/dist/Plugin.d.ts.map +1 -0
- package/dist/Plugin.js +249 -0
- package/dist/Plugin.js.map +1 -0
- package/dist/PluginRuntime.d.ts +3186 -0
- package/dist/PluginRuntime.d.ts.map +1 -0
- package/dist/PluginRuntime.js +331 -0
- package/dist/PluginRuntime.js.map +1 -0
- package/dist/Runner.d.ts +1 -0
- package/dist/Runner.js +124 -0
- package/dist/Runner.js.map +1 -0
- package/dist/ToolFile.d.ts +23 -0
- package/dist/ToolFile.d.ts.map +1 -0
- package/dist/ToolFile.js +33 -0
- package/dist/ToolFile.js.map +1 -0
- package/dist/Trigger.d.ts +358 -0
- package/dist/Trigger.d.ts.map +1 -0
- package/dist/Trigger.js +287 -0
- package/dist/Trigger.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +24 -0
- package/dist/internal/auth-context.d.ts +23 -0
- package/dist/internal/auth-context.d.ts.map +1 -0
- package/dist/internal/auth-context.js +1 -0
- package/dist/internal/auth-execution.d.ts +27 -0
- package/dist/internal/auth-execution.d.ts.map +1 -0
- package/dist/internal/auth-execution.js +66 -0
- package/dist/internal/auth-execution.js.map +1 -0
- package/dist/internal/auth-runtime.d.ts +5 -0
- package/dist/internal/auth-runtime.d.ts.map +1 -0
- package/dist/internal/auth-runtime.js +16 -0
- package/dist/internal/auth-runtime.js.map +1 -0
- package/dist/internal/capabilities.d.ts +24 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +22 -0
- package/dist/internal/capabilities.js.map +1 -0
- package/dist/internal/children.d.ts +34 -0
- package/dist/internal/children.d.ts.map +1 -0
- package/dist/internal/children.js +53 -0
- package/dist/internal/children.js.map +1 -0
- package/dist/internal/collection-utils.d.ts +4 -0
- package/dist/internal/collection-utils.d.ts.map +1 -0
- package/dist/internal/collection-utils.js +6 -0
- package/dist/internal/collection-utils.js.map +1 -0
- package/dist/internal/dual/actions.d.ts +33 -0
- package/dist/internal/dual/actions.d.ts.map +1 -0
- package/dist/internal/dual/actions.js +26 -0
- package/dist/internal/dual/actions.js.map +1 -0
- package/dist/internal/dual/invoke.d.ts +63 -0
- package/dist/internal/dual/invoke.d.ts.map +1 -0
- package/dist/internal/dual/invoke.js +75 -0
- package/dist/internal/dual/invoke.js.map +1 -0
- package/dist/internal/dual/registry.d.ts +125 -0
- package/dist/internal/dual/registry.d.ts.map +1 -0
- package/dist/internal/dual/registry.js +172 -0
- package/dist/internal/dual/registry.js.map +1 -0
- package/dist/internal/dual/triggers.d.ts +29 -0
- package/dist/internal/dual/triggers.d.ts.map +1 -0
- package/dist/internal/dual/triggers.js +26 -0
- package/dist/internal/dual/triggers.js.map +1 -0
- package/dist/internal/handler-context.d.ts +9 -0
- package/dist/internal/handler-context.d.ts.map +1 -0
- package/dist/internal/handler-context.js +31 -0
- package/dist/internal/handler-context.js.map +1 -0
- package/dist/internal/identifier.d.ts +6 -0
- package/dist/internal/identifier.d.ts.map +1 -0
- package/dist/internal/identifier.js +28 -0
- package/dist/internal/identifier.js.map +1 -0
- package/dist/internal/plugin-handlers.d.ts +38 -0
- package/dist/internal/plugin-handlers.d.ts.map +1 -0
- package/dist/internal/plugin-handlers.js +52 -0
- package/dist/internal/plugin-handlers.js.map +1 -0
- package/dist/internal/proto.d.ts +7 -0
- package/dist/internal/proto.d.ts.map +1 -0
- package/dist/internal/proto.js +10 -0
- package/dist/internal/proto.js.map +1 -0
- package/dist/internal/schema-runtime.d.ts +6 -0
- package/dist/internal/schema-runtime.d.ts.map +1 -0
- package/dist/internal/schema-runtime.js +10 -0
- package/dist/internal/schema-runtime.js.map +1 -0
- package/dist/internal/trigger-runtime-shared.d.ts +41 -0
- package/dist/internal/trigger-runtime-shared.d.ts.map +1 -0
- package/dist/internal/trigger-runtime-shared.js +132 -0
- package/dist/internal/trigger-runtime-shared.js.map +1 -0
- package/dist/internal/trigger-runtime.d.ts +12 -0
- package/dist/internal/trigger-runtime.d.ts.map +1 -0
- package/dist/internal/trigger-runtime.js +95 -0
- package/dist/internal/trigger-runtime.js.map +1 -0
- package/dist/internal/types.d.ts +7 -0
- package/dist/internal/types.d.ts.map +1 -0
- package/dist/internal/types.js +1 -0
- package/dist/remote-runtime.d.ts +585 -0
- package/dist/remote-runtime.d.ts.map +1 -0
- package/dist/remote-runtime.js +367 -0
- package/dist/remote-runtime.js.map +1 -0
- package/package.json +55 -4
- package/src/Action.ts +370 -0
- package/src/AgentChannel.ts +860 -0
- package/src/AgentChannelConformance.ts +124 -0
- package/src/AgentChannelRuntime.ts +616 -0
- package/src/AiProvider.ts +255 -0
- package/src/AuthMethod.ts +954 -0
- package/src/AuthMethodBinding.ts +112 -0
- package/src/AuthMethodExecution.ts +542 -0
- package/src/ConnectionResolver.ts +265 -0
- package/src/DefinitionError.ts +115 -0
- package/src/DualRegistry.ts +152 -0
- package/src/DualRuntime.ts +1081 -0
- package/src/Files.ts +89 -0
- package/src/Group.ts +292 -0
- package/src/Http.ts +1205 -0
- package/src/Mcp.ts +299 -0
- package/src/OAuth2TokenRefresher.ts +22 -0
- package/src/OAuthFlow.ts +874 -0
- package/src/Plugin.ts +912 -0
- package/src/PluginRuntime.ts +414 -0
- package/src/Runner.ts +248 -0
- package/src/ToolFile.ts +28 -0
- package/src/Trigger.ts +722 -0
- package/src/index.ts +158 -0
- package/src/internal/auth-context.ts +27 -0
- package/src/internal/auth-execution.ts +241 -0
- package/src/internal/auth-runtime.ts +20 -0
- package/src/internal/capabilities.ts +55 -0
- package/src/internal/children.ts +126 -0
- package/src/internal/collection-utils.ts +8 -0
- package/src/internal/dual/actions.ts +116 -0
- package/src/internal/dual/invoke.ts +307 -0
- package/src/internal/dual/registry.ts +340 -0
- package/src/internal/dual/triggers.ts +128 -0
- package/src/internal/handler-context.ts +57 -0
- package/src/internal/identifier.ts +27 -0
- package/src/internal/plugin-handlers.ts +146 -0
- package/src/internal/proto.ts +8 -0
- package/src/internal/schema-runtime.ts +15 -0
- package/src/internal/trigger-runtime-shared.ts +449 -0
- package/src/internal/trigger-runtime.ts +223 -0
- package/src/internal/types.ts +12 -0
- package/src/remote-runtime.ts +469 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/** Plugin handler services and their registration. */
|
|
2
|
+
import { Context, Effect, Predicate } from "effect";
|
|
3
|
+
|
|
4
|
+
import * as Action from "../Action.ts";
|
|
5
|
+
import * as AgentChannel from "../AgentChannel.ts";
|
|
6
|
+
import type * as AuthMethod from "../AuthMethod.ts";
|
|
7
|
+
import type * as Group from "../Group.ts";
|
|
8
|
+
import type { Any } from "../Plugin.ts";
|
|
9
|
+
import * as Trigger from "../Trigger.ts";
|
|
10
|
+
|
|
11
|
+
import { walkCapabilities } from "./capabilities.ts";
|
|
12
|
+
import { handlerGroupKey, withoutGroups } from "./handler-context.ts";
|
|
13
|
+
import { MachineIdSeparator } from "./identifier.ts";
|
|
14
|
+
import type { IsGenericArray, JoinPrefix } from "./types.ts";
|
|
15
|
+
|
|
16
|
+
type LocalTriggerEntriesFromTriggers<
|
|
17
|
+
Triggers extends readonly Trigger.Any[],
|
|
18
|
+
Prefix extends string,
|
|
19
|
+
AllowedMethods extends readonly AuthMethod.Any[],
|
|
20
|
+
> = Triggers[number] extends infer TriggerDef
|
|
21
|
+
? TriggerDef extends Trigger.Any
|
|
22
|
+
? {
|
|
23
|
+
readonly localId: JoinPrefix<Prefix, TriggerDef["identifier"]>;
|
|
24
|
+
readonly trigger: TriggerDef;
|
|
25
|
+
readonly authMethods: AllowedMethods;
|
|
26
|
+
}
|
|
27
|
+
: never
|
|
28
|
+
: never;
|
|
29
|
+
|
|
30
|
+
type LocalTriggerEntriesFromGroups<
|
|
31
|
+
GroupDef extends Group.Any,
|
|
32
|
+
Prefix extends string,
|
|
33
|
+
AllowedMethods extends readonly AuthMethod.Any[],
|
|
34
|
+
> = GroupDef extends unknown
|
|
35
|
+
?
|
|
36
|
+
| LocalTriggerEntriesFromTriggers<
|
|
37
|
+
GroupDef["triggers"],
|
|
38
|
+
JoinPrefix<Prefix, GroupDef["identifier"]>,
|
|
39
|
+
AllowedMethods
|
|
40
|
+
>
|
|
41
|
+
| (IsGenericArray<GroupDef["groups"]> extends true
|
|
42
|
+
? LocalTriggerEntriesFromTriggers<readonly Trigger.Any[], string, AllowedMethods>
|
|
43
|
+
: LocalTriggerEntriesFromGroups<
|
|
44
|
+
GroupDef["groups"][number],
|
|
45
|
+
JoinPrefix<Prefix, GroupDef["identifier"]>,
|
|
46
|
+
AllowedMethods
|
|
47
|
+
>)
|
|
48
|
+
: never;
|
|
49
|
+
|
|
50
|
+
export type LocalTriggerEntries<P extends Any> =
|
|
51
|
+
| LocalTriggerEntriesFromTriggers<P["triggers"], "", P["authMethods"]>
|
|
52
|
+
| LocalTriggerEntriesFromGroups<P["groups"][number], "", P["authMethods"]>;
|
|
53
|
+
|
|
54
|
+
export type CanonicalTriggerId<
|
|
55
|
+
P extends Any,
|
|
56
|
+
LocalId extends string,
|
|
57
|
+
> = `${P["identifier"]}${typeof MachineIdSeparator}${LocalId}`;
|
|
58
|
+
|
|
59
|
+
/** Keyed by the plugin's capabilities, which `Plugin.provide` keeps, so a Layer serves only them. */
|
|
60
|
+
export interface ActionHandlerService<
|
|
61
|
+
in out PluginId extends string,
|
|
62
|
+
in out Actions extends readonly unknown[],
|
|
63
|
+
in out Groups extends readonly unknown[],
|
|
64
|
+
> {
|
|
65
|
+
readonly _: unique symbol;
|
|
66
|
+
readonly pluginId: PluginId;
|
|
67
|
+
readonly actions: Actions;
|
|
68
|
+
readonly groups: Groups;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type ActionHandlerServiceOf<P extends Any> = ActionHandlerService<
|
|
72
|
+
P["identifier"],
|
|
73
|
+
P["actions"],
|
|
74
|
+
P["groups"]
|
|
75
|
+
>;
|
|
76
|
+
|
|
77
|
+
export type HandlerServices<P extends Any> =
|
|
78
|
+
| ActionHandlerServiceOf<P>
|
|
79
|
+
| ([P["agentChannels"][number]] extends [never]
|
|
80
|
+
? never
|
|
81
|
+
: AgentChannel.Handler<`${P["identifier"]}/${P["agentChannels"][number]["identifier"]}`>)
|
|
82
|
+
| (LocalTriggerEntries<P> extends infer Entry
|
|
83
|
+
? Entry extends { readonly localId: infer LocalId extends string }
|
|
84
|
+
? Trigger.Handler<CanonicalTriggerId<P, LocalId>>
|
|
85
|
+
: never
|
|
86
|
+
: never);
|
|
87
|
+
|
|
88
|
+
interface Declarations {
|
|
89
|
+
readonly actions: unknown;
|
|
90
|
+
readonly triggers: unknown;
|
|
91
|
+
readonly agentChannels: unknown;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Missing handler declarations are builder defects, not expected failures, so
|
|
95
|
+
they intentionally throw instead of entering the Effect failure channel. */
|
|
96
|
+
const missingDeclaration = (kind: string, localId: string, pluginId: string): never => {
|
|
97
|
+
throw new Error(`missing ${kind} handler for "${localId}" in plugin "${pluginId}"`);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const getNestedHandler = (handlers: unknown, localId: string): unknown => {
|
|
101
|
+
let current = handlers;
|
|
102
|
+
for (const segment of localId.split(MachineIdSeparator)) {
|
|
103
|
+
if (!Predicate.hasProperty(current, segment)) return undefined;
|
|
104
|
+
current = current[segment];
|
|
105
|
+
}
|
|
106
|
+
return current;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/** Register a plugin's handlers as one Context group keyed by the plugin. */
|
|
110
|
+
export const toHandlers = (
|
|
111
|
+
plugin: Any,
|
|
112
|
+
handlers: Declarations,
|
|
113
|
+
): Effect.Effect<Context.Context<never>> =>
|
|
114
|
+
Effect.gen(function* () {
|
|
115
|
+
const services = withoutGroups(yield* Effect.context());
|
|
116
|
+
const map = new Map<string, unknown>();
|
|
117
|
+
// A declared but invalid handler, such as `null` from JavaScript, fails when it is used.
|
|
118
|
+
const find = (kind: string, declarations: unknown, localId: string) => {
|
|
119
|
+
const handler = getNestedHandler(declarations, localId);
|
|
120
|
+
return handler === undefined ? missingDeclaration(kind, localId, plugin.identifier) : handler;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
for (const entry of walkCapabilities(plugin, owner => owner.actions)) {
|
|
124
|
+
map.set(Action.handlerKey(entry.canonicalId), {
|
|
125
|
+
actionId: entry.canonicalId,
|
|
126
|
+
context: services,
|
|
127
|
+
handler: find("action", handlers.actions, entry.localId),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
for (const entry of walkCapabilities(plugin, owner => owner.triggers)) {
|
|
131
|
+
map.set(Trigger.handlerKey(entry.canonicalId), {
|
|
132
|
+
context: services,
|
|
133
|
+
runtime: find("trigger", handlers.triggers, entry.localId),
|
|
134
|
+
triggerId: entry.canonicalId,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
for (const channel of plugin.agentChannels) {
|
|
138
|
+
const channelId = `${plugin.identifier}/${channel.identifier}`;
|
|
139
|
+
map.set(AgentChannel.handlerKey(channelId), {
|
|
140
|
+
channelId,
|
|
141
|
+
context: services,
|
|
142
|
+
runtime: find("agent channel", handlers.agentChannels, channel.identifier),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return Context.makeUnsafe(new Map([[handlerGroupKey(plugin.identifier), map]]));
|
|
146
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
export function decodeJson<SchemaDef extends Schema.Top>(
|
|
4
|
+
schema: SchemaDef,
|
|
5
|
+
value: unknown,
|
|
6
|
+
): Effect.Effect<SchemaDef["Type"], Schema.SchemaError, SchemaDef["DecodingServices"]> {
|
|
7
|
+
return Schema.decodeUnknownEffect(Schema.toCodecJson(schema))(value);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const decodeJsonMapError = <SchemaDef extends Schema.Top, Error>(
|
|
11
|
+
schema: SchemaDef,
|
|
12
|
+
value: unknown,
|
|
13
|
+
mapError: (error: Schema.SchemaError) => Error,
|
|
14
|
+
): Effect.Effect<SchemaDef["Type"], Error, SchemaDef["DecodingServices"]> =>
|
|
15
|
+
decodeJson(schema, value).pipe(Effect.mapError(mapError));
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import type { Context } from "effect";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
import type { ConnectionResolutionContext, Service } from "../ConnectionResolver.ts";
|
|
5
|
+
import * as Trigger from "../Trigger.ts";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
authRuntimeContext,
|
|
9
|
+
noAuthRuntimeContext,
|
|
10
|
+
failConnectionIdNotAllowed,
|
|
11
|
+
resolveRuntimeConnection,
|
|
12
|
+
type AuthResolutionRequirements,
|
|
13
|
+
type AuthSchemaRequirements,
|
|
14
|
+
type RuntimeConnectionErrorsFor,
|
|
15
|
+
toNonEmptyArray,
|
|
16
|
+
} from "./auth-execution.ts";
|
|
17
|
+
import { findHandler } from "./handler-context.ts";
|
|
18
|
+
import { decodeJson, decodeJsonMapError } from "./schema-runtime.ts";
|
|
19
|
+
|
|
20
|
+
type ConfigRequirements<TriggerDef extends Trigger.Any> =
|
|
21
|
+
Trigger.ConfigSchema<TriggerDef>["DecodingServices"];
|
|
22
|
+
|
|
23
|
+
type StateDecodingRequirements<TriggerDef extends Trigger.Any> =
|
|
24
|
+
Trigger.StateSchema<TriggerDef> extends Schema.Top
|
|
25
|
+
? Exclude<Trigger.StateSchema<TriggerDef>, undefined>["DecodingServices"]
|
|
26
|
+
: never;
|
|
27
|
+
|
|
28
|
+
type StateEncodingRequirements<TriggerDef extends Trigger.Any> =
|
|
29
|
+
Trigger.StateSchema<TriggerDef> extends Schema.Top
|
|
30
|
+
? Exclude<Trigger.StateSchema<TriggerDef>, undefined>["EncodingServices"]
|
|
31
|
+
: never;
|
|
32
|
+
|
|
33
|
+
type OutputEncodingRequirements<TriggerDef extends Trigger.Any> =
|
|
34
|
+
Trigger.OutputSchema<TriggerDef>["EncodingServices"];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Trigger hooks may fail with arbitrary app-defined errors, so phase failures
|
|
38
|
+
* deliberately widen to `unknown`. The alias keeps that decision visible in
|
|
39
|
+
* the phase signatures.
|
|
40
|
+
*/
|
|
41
|
+
export type TriggerAppError<_TriggerDef extends Trigger.Any> = unknown;
|
|
42
|
+
|
|
43
|
+
export type TriggerEncodedState<TriggerDef extends Trigger.Any> =
|
|
44
|
+
Trigger.StateSchema<TriggerDef> extends Schema.Top
|
|
45
|
+
? Exclude<Trigger.StateSchema<TriggerDef>, undefined>["Encoded"] | undefined
|
|
46
|
+
: undefined;
|
|
47
|
+
|
|
48
|
+
export type TriggerEncodedOutput<TriggerDef extends Trigger.Any> =
|
|
49
|
+
Trigger.OutputSchema<TriggerDef>["Encoded"];
|
|
50
|
+
|
|
51
|
+
export type TriggerIdOf<Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>> =
|
|
52
|
+
Entry["triggerId"];
|
|
53
|
+
export type EntryTrigger<Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>> =
|
|
54
|
+
Entry["trigger"];
|
|
55
|
+
export type EntryAuthMethods<Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>> =
|
|
56
|
+
Entry["authMethods"];
|
|
57
|
+
type EntryHandler<Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>> = Trigger.Handler<
|
|
58
|
+
TriggerIdOf<Entry>
|
|
59
|
+
>;
|
|
60
|
+
|
|
61
|
+
export type TriggerRuntimeRequirements<
|
|
62
|
+
Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>,
|
|
63
|
+
Phase extends Trigger.RuntimePhase,
|
|
64
|
+
> =
|
|
65
|
+
| EntryHandler<Entry>
|
|
66
|
+
| ConfigRequirements<EntryTrigger<Entry>>
|
|
67
|
+
| StateDecodingRequirements<EntryTrigger<Entry>>
|
|
68
|
+
| (Phase extends "activate" | "verify" | "parse" | "poll"
|
|
69
|
+
? StateEncodingRequirements<EntryTrigger<Entry>>
|
|
70
|
+
: never)
|
|
71
|
+
| (Phase extends "parse" | "poll" ? OutputEncodingRequirements<EntryTrigger<Entry>> : never)
|
|
72
|
+
| ([EntryAuthMethods<Entry>[number]] extends [never]
|
|
73
|
+
? never
|
|
74
|
+
:
|
|
75
|
+
| Service
|
|
76
|
+
| AuthSchemaRequirements<EntryAuthMethods<Entry>>
|
|
77
|
+
| AuthResolutionRequirements<EntryAuthMethods<Entry>>);
|
|
78
|
+
|
|
79
|
+
export const decodeConfig = <Config extends Schema.Top>(
|
|
80
|
+
triggerId: string,
|
|
81
|
+
schema: Config,
|
|
82
|
+
value: unknown,
|
|
83
|
+
): Effect.Effect<Config["Type"], Trigger.InvalidTriggerConfigError, Config["DecodingServices"]> =>
|
|
84
|
+
decodeJsonMapError(
|
|
85
|
+
schema,
|
|
86
|
+
value,
|
|
87
|
+
error => new Trigger.InvalidTriggerConfigError({ description: error.message, triggerId }),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const decodeStateValue = (): Effect.Effect<undefined> => Effect.as(Effect.void, undefined);
|
|
91
|
+
|
|
92
|
+
function decodeStateSchema<State extends Schema.Top>(
|
|
93
|
+
schema: State,
|
|
94
|
+
value: undefined,
|
|
95
|
+
): Effect.Effect<State["Type"] | undefined>;
|
|
96
|
+
function decodeStateSchema<State extends Schema.Top>(
|
|
97
|
+
schema: State,
|
|
98
|
+
value: unknown,
|
|
99
|
+
): Effect.Effect<State["Type"] | undefined, Schema.SchemaError, State["DecodingServices"]>;
|
|
100
|
+
function decodeStateSchema<State extends Schema.Top>(
|
|
101
|
+
schema: State,
|
|
102
|
+
value: unknown,
|
|
103
|
+
): Effect.Effect<State["Type"] | undefined, Schema.SchemaError, State["DecodingServices"]> {
|
|
104
|
+
if (value === undefined) {
|
|
105
|
+
return decodeStateValue();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return decodeJson(schema, value);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function decodeState(
|
|
112
|
+
triggerId: string,
|
|
113
|
+
phase: Trigger.RuntimePhase,
|
|
114
|
+
schema: undefined,
|
|
115
|
+
value: unknown,
|
|
116
|
+
): Effect.Effect<undefined, Trigger.InvalidTriggerStateError>;
|
|
117
|
+
export function decodeState<State extends Schema.Top>(
|
|
118
|
+
triggerId: string,
|
|
119
|
+
phase: Trigger.RuntimePhase,
|
|
120
|
+
schema: State,
|
|
121
|
+
value: unknown,
|
|
122
|
+
): Effect.Effect<
|
|
123
|
+
State["Type"] | undefined,
|
|
124
|
+
Trigger.InvalidTriggerStateError,
|
|
125
|
+
State["DecodingServices"]
|
|
126
|
+
>;
|
|
127
|
+
export function decodeState<State extends Schema.Top | undefined>(
|
|
128
|
+
triggerId: string,
|
|
129
|
+
phase: Trigger.RuntimePhase,
|
|
130
|
+
schema: State,
|
|
131
|
+
value: unknown,
|
|
132
|
+
): Effect.Effect<unknown, Trigger.InvalidTriggerStateError, unknown> {
|
|
133
|
+
if (schema === undefined) {
|
|
134
|
+
return value === undefined
|
|
135
|
+
? decodeStateValue()
|
|
136
|
+
: Effect.fail(
|
|
137
|
+
new Trigger.InvalidTriggerStateError({
|
|
138
|
+
description: "state is not supported for this trigger",
|
|
139
|
+
location: "input",
|
|
140
|
+
phase,
|
|
141
|
+
triggerId,
|
|
142
|
+
}),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return decodeStateSchema(schema, value).pipe(
|
|
147
|
+
Effect.mapError(
|
|
148
|
+
error =>
|
|
149
|
+
new Trigger.InvalidTriggerStateError({
|
|
150
|
+
description: error.message,
|
|
151
|
+
location: "input",
|
|
152
|
+
phase,
|
|
153
|
+
triggerId,
|
|
154
|
+
}),
|
|
155
|
+
),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const encodeStateSchema = <State extends Schema.Top>(
|
|
160
|
+
triggerId: string,
|
|
161
|
+
phase: Trigger.RuntimePhase,
|
|
162
|
+
schema: State,
|
|
163
|
+
value: State["Type"] | undefined,
|
|
164
|
+
): Effect.Effect<
|
|
165
|
+
State["Encoded"] | undefined,
|
|
166
|
+
Trigger.InvalidTriggerStateError,
|
|
167
|
+
State["EncodingServices"]
|
|
168
|
+
> => {
|
|
169
|
+
if (value === undefined) {
|
|
170
|
+
return Effect.void;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return Schema.encodeEffect(schema)(value).pipe(
|
|
174
|
+
Effect.mapError(
|
|
175
|
+
error =>
|
|
176
|
+
new Trigger.InvalidTriggerStateError({
|
|
177
|
+
description: error.message,
|
|
178
|
+
location: "result",
|
|
179
|
+
phase,
|
|
180
|
+
triggerId,
|
|
181
|
+
}),
|
|
182
|
+
),
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export function validateStateResult(
|
|
187
|
+
triggerId: string,
|
|
188
|
+
phase: Trigger.RuntimePhase,
|
|
189
|
+
schema: undefined,
|
|
190
|
+
value: undefined,
|
|
191
|
+
): Effect.Effect<undefined, Trigger.InvalidTriggerStateError>;
|
|
192
|
+
export function validateStateResult<State extends Schema.Top>(
|
|
193
|
+
triggerId: string,
|
|
194
|
+
phase: Trigger.RuntimePhase,
|
|
195
|
+
schema: State,
|
|
196
|
+
value: State["Type"] | undefined,
|
|
197
|
+
): Effect.Effect<
|
|
198
|
+
State["Encoded"] | undefined,
|
|
199
|
+
Trigger.InvalidTriggerStateError,
|
|
200
|
+
State["EncodingServices"]
|
|
201
|
+
>;
|
|
202
|
+
export function validateStateResult<State extends Schema.Top | undefined>(
|
|
203
|
+
triggerId: string,
|
|
204
|
+
phase: Trigger.RuntimePhase,
|
|
205
|
+
schema: State,
|
|
206
|
+
value: Trigger.StateValue<State>,
|
|
207
|
+
): Effect.Effect<unknown, Trigger.InvalidTriggerStateError, unknown> {
|
|
208
|
+
if (schema === undefined) {
|
|
209
|
+
return value === undefined
|
|
210
|
+
? decodeStateValue()
|
|
211
|
+
: Effect.fail(
|
|
212
|
+
new Trigger.InvalidTriggerStateError({
|
|
213
|
+
description: "state is not supported for this trigger",
|
|
214
|
+
location: "result",
|
|
215
|
+
phase,
|
|
216
|
+
triggerId,
|
|
217
|
+
}),
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return encodeStateSchema(triggerId, phase, schema, value);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const KeyedEventEnvelope = Schema.Struct({ key: Schema.NonEmptyString, payload: Schema.Unknown });
|
|
225
|
+
|
|
226
|
+
type KeyedEventEnvelope = typeof KeyedEventEnvelope.Type;
|
|
227
|
+
|
|
228
|
+
const eventKeysAreUnique = (events: readonly KeyedEventEnvelope[]) => {
|
|
229
|
+
const seen = new Set<string>();
|
|
230
|
+
for (const event of events) {
|
|
231
|
+
if (seen.has(event.key)) {
|
|
232
|
+
return `duplicate event key "${event.key}"`;
|
|
233
|
+
}
|
|
234
|
+
seen.add(event.key);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return true;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const KeyedEventEnvelopes = Schema.Array(KeyedEventEnvelope).check(
|
|
241
|
+
Schema.makeFilter(eventKeysAreUnique),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const mapOutputError =
|
|
245
|
+
(triggerId: string, phase: "parse" | "poll") => (error: Schema.SchemaError) =>
|
|
246
|
+
new Trigger.InvalidTriggerOutputError({ description: error.message, phase, triggerId });
|
|
247
|
+
|
|
248
|
+
export const validateOutputs = <Output extends Schema.Top>(
|
|
249
|
+
triggerId: string,
|
|
250
|
+
phase: "parse" | "poll",
|
|
251
|
+
schema: Output,
|
|
252
|
+
events: unknown,
|
|
253
|
+
): Effect.Effect<
|
|
254
|
+
readonly Trigger.KeyedEvent<Output["Encoded"]>[],
|
|
255
|
+
Trigger.InvalidTriggerOutputError,
|
|
256
|
+
Output["EncodingServices"]
|
|
257
|
+
> =>
|
|
258
|
+
Schema.decodeUnknownEffect(KeyedEventEnvelopes)(events).pipe(
|
|
259
|
+
Effect.flatMap(decodedEvents =>
|
|
260
|
+
Effect.forEach(decodedEvents, event =>
|
|
261
|
+
Schema.encodeEffect(schema)(event.payload).pipe(
|
|
262
|
+
Effect.flatMap(encoded => Schema.decodeUnknownEffect(Schema.Json)(encoded)),
|
|
263
|
+
Effect.map(payload => ({ key: event.key, payload: payload as Output["Encoded"] })),
|
|
264
|
+
),
|
|
265
|
+
),
|
|
266
|
+
),
|
|
267
|
+
Effect.mapError(mapOutputError(triggerId, phase)),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
interface RuntimeHook<Hook> {
|
|
271
|
+
readonly hook: Hook;
|
|
272
|
+
readonly context: Context.Context<never>;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
type WebhookPhase = "activate" | "deactivate" | "verify" | "parse";
|
|
276
|
+
|
|
277
|
+
type WebhookHook<Phase extends WebhookPhase> = NonNullable<
|
|
278
|
+
Trigger.WebhookRuntime<Schema.Top, Schema.Top, Schema.Top | undefined, any, any, any>[Phase]
|
|
279
|
+
>;
|
|
280
|
+
|
|
281
|
+
type PollHook = NonNullable<
|
|
282
|
+
Trigger.PollingRuntime<Schema.Top, Schema.Top, Schema.Top | undefined, any, any, any>["poll"]
|
|
283
|
+
>;
|
|
284
|
+
|
|
285
|
+
const getTriggerHandler = <Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>>(
|
|
286
|
+
entry: Entry,
|
|
287
|
+
): Effect.Effect<
|
|
288
|
+
EntryHandler<Entry>,
|
|
289
|
+
Trigger.UnsupportedTriggerRuntimeError,
|
|
290
|
+
EntryHandler<Entry>
|
|
291
|
+
> =>
|
|
292
|
+
Effect.context<EntryHandler<Entry>>().pipe(
|
|
293
|
+
Effect.flatMap(context => {
|
|
294
|
+
const handler = findHandler(
|
|
295
|
+
context,
|
|
296
|
+
entry.providerId,
|
|
297
|
+
Trigger.handlerKey(entry.triggerId),
|
|
298
|
+
) as EntryHandler<Entry> | undefined;
|
|
299
|
+
|
|
300
|
+
return handler === undefined
|
|
301
|
+
? Effect.fail(
|
|
302
|
+
new Trigger.UnsupportedTriggerRuntimeError({
|
|
303
|
+
kind: entry.trigger.kind,
|
|
304
|
+
phase: entry.trigger.kind === "polling" ? "poll" : "parse",
|
|
305
|
+
triggerId: entry.triggerId,
|
|
306
|
+
}),
|
|
307
|
+
)
|
|
308
|
+
: Effect.succeed(handler);
|
|
309
|
+
}),
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
export const requireWebhookHook = <
|
|
313
|
+
Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>,
|
|
314
|
+
Phase extends WebhookPhase,
|
|
315
|
+
>(
|
|
316
|
+
entry: Entry,
|
|
317
|
+
phase: Phase,
|
|
318
|
+
): Effect.Effect<
|
|
319
|
+
RuntimeHook<WebhookHook<Phase>>,
|
|
320
|
+
Trigger.UnsupportedTriggerRuntimeError,
|
|
321
|
+
EntryHandler<Entry>
|
|
322
|
+
> => {
|
|
323
|
+
if (entry.trigger.kind !== "webhook") {
|
|
324
|
+
return Effect.fail(
|
|
325
|
+
new Trigger.UnsupportedTriggerRuntimeError({
|
|
326
|
+
kind: entry.trigger.kind,
|
|
327
|
+
phase,
|
|
328
|
+
triggerId: entry.triggerId,
|
|
329
|
+
}),
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return getTriggerHandler(entry).pipe(
|
|
334
|
+
Effect.flatMap(handler => {
|
|
335
|
+
const hook = (handler.runtime as Trigger.WebhookRuntime<any, any, any, any, any, any>)[phase];
|
|
336
|
+
|
|
337
|
+
if (hook === undefined) {
|
|
338
|
+
return Effect.fail(
|
|
339
|
+
new Trigger.UnsupportedTriggerRuntimeError({
|
|
340
|
+
kind: entry.trigger.kind,
|
|
341
|
+
phase,
|
|
342
|
+
triggerId: entry.triggerId,
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return Effect.succeed({ context: handler.context, hook } as RuntimeHook<WebhookHook<Phase>>);
|
|
348
|
+
}),
|
|
349
|
+
);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
export const requirePollingHook = <Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>>(
|
|
353
|
+
entry: Entry,
|
|
354
|
+
): Effect.Effect<
|
|
355
|
+
RuntimeHook<PollHook>,
|
|
356
|
+
Trigger.UnsupportedTriggerRuntimeError,
|
|
357
|
+
EntryHandler<Entry>
|
|
358
|
+
> => {
|
|
359
|
+
if (entry.trigger.kind !== "polling") {
|
|
360
|
+
return Effect.fail(
|
|
361
|
+
new Trigger.UnsupportedTriggerRuntimeError({
|
|
362
|
+
kind: entry.trigger.kind,
|
|
363
|
+
phase: "poll",
|
|
364
|
+
triggerId: entry.triggerId,
|
|
365
|
+
}),
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return getTriggerHandler(entry).pipe(
|
|
370
|
+
Effect.flatMap(handler => {
|
|
371
|
+
const hook = (handler.runtime as Trigger.PollingRuntime<any, any, any, any, any, any>).poll;
|
|
372
|
+
|
|
373
|
+
if (hook === undefined) {
|
|
374
|
+
return Effect.fail(
|
|
375
|
+
new Trigger.UnsupportedTriggerRuntimeError({
|
|
376
|
+
kind: entry.trigger.kind,
|
|
377
|
+
phase: "poll",
|
|
378
|
+
triggerId: entry.triggerId,
|
|
379
|
+
}),
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return Effect.succeed({ context: handler.context, hook } as RuntimeHook<PollHook>);
|
|
384
|
+
}),
|
|
385
|
+
);
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
export const withRuntimeContext: <
|
|
389
|
+
Entry extends Trigger.RuntimeTriggerEntry<any, any, any, any>,
|
|
390
|
+
Phase extends Trigger.RuntimePhase,
|
|
391
|
+
Result,
|
|
392
|
+
>(
|
|
393
|
+
entry: Entry,
|
|
394
|
+
phase: Phase,
|
|
395
|
+
connectionId: string | undefined,
|
|
396
|
+
context: ConnectionResolutionContext | undefined,
|
|
397
|
+
run: (
|
|
398
|
+
context: Trigger.RuntimeContext<EntryAuthMethods<Entry>>,
|
|
399
|
+
) => Effect.Effect<
|
|
400
|
+
Result,
|
|
401
|
+
TriggerAppError<EntryTrigger<Entry>> | RuntimeConnectionErrorsFor<EntryAuthMethods<Entry>>,
|
|
402
|
+
TriggerRuntimeRequirements<Entry, Phase>
|
|
403
|
+
>,
|
|
404
|
+
) => Effect.Effect<
|
|
405
|
+
Result,
|
|
406
|
+
TriggerAppError<EntryTrigger<Entry>> | RuntimeConnectionErrorsFor<EntryAuthMethods<Entry>>,
|
|
407
|
+
TriggerRuntimeRequirements<Entry, Phase>
|
|
408
|
+
> = (
|
|
409
|
+
entry: Trigger.RuntimeTriggerEntry,
|
|
410
|
+
phase: Trigger.RuntimePhase,
|
|
411
|
+
connectionId: string | undefined,
|
|
412
|
+
context: ConnectionResolutionContext | undefined,
|
|
413
|
+
run: (context: never) => Effect.Effect<unknown, unknown, unknown>,
|
|
414
|
+
) => {
|
|
415
|
+
const requiredAuthMethods = toNonEmptyArray(entry.authMethods);
|
|
416
|
+
const runtimeContext = <AuthContext extends object>(authContext: AuthContext) =>
|
|
417
|
+
context === undefined ? authContext : ({ ...context, ...authContext } as const);
|
|
418
|
+
|
|
419
|
+
if (requiredAuthMethods === undefined) {
|
|
420
|
+
if (connectionId !== undefined) {
|
|
421
|
+
return failConnectionIdNotAllowed(
|
|
422
|
+
"trigger",
|
|
423
|
+
entry.triggerId,
|
|
424
|
+
phase,
|
|
425
|
+
entry.providerId,
|
|
426
|
+
connectionId,
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return run(runtimeContext(noAuthRuntimeContext()) as never) as never;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Only an explicit false skips auth for definitions built outside the SDK.
|
|
434
|
+
if (entry.trigger.requireAuth === false && connectionId === undefined) {
|
|
435
|
+
return run(runtimeContext(noAuthRuntimeContext()) as never) as never;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return resolveRuntimeConnection(
|
|
439
|
+
"trigger",
|
|
440
|
+
entry.triggerId,
|
|
441
|
+
phase,
|
|
442
|
+
entry.providerId,
|
|
443
|
+
requiredAuthMethods,
|
|
444
|
+
connectionId,
|
|
445
|
+
context,
|
|
446
|
+
).pipe(
|
|
447
|
+
Effect.flatMap(binding => run(runtimeContext(authRuntimeContext(binding)) as never)),
|
|
448
|
+
) as never;
|
|
449
|
+
};
|