@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
package/src/Action.ts
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical action definition builders and types for the Dual SDK.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import type { Context, Pipeable, SchemaIssue } from "effect";
|
|
7
|
+
import {
|
|
8
|
+
Array,
|
|
9
|
+
DateTime,
|
|
10
|
+
Duration,
|
|
11
|
+
Effect,
|
|
12
|
+
Match,
|
|
13
|
+
Number,
|
|
14
|
+
Option,
|
|
15
|
+
pipe,
|
|
16
|
+
Predicate,
|
|
17
|
+
Schema,
|
|
18
|
+
} from "effect";
|
|
19
|
+
|
|
20
|
+
import { Headers, HttpClientError } from "effect/http";
|
|
21
|
+
|
|
22
|
+
import type * as AuthMethod from "./AuthMethod.ts";
|
|
23
|
+
import type { ContextForMethods } from "./internal/auth-context.ts";
|
|
24
|
+
import { validateIdentifier } from "./internal/identifier.ts";
|
|
25
|
+
import { PipeableProto } from "./internal/proto.ts";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @since 0.0.0
|
|
29
|
+
* @category type ids
|
|
30
|
+
*/
|
|
31
|
+
export const TypeId = "@dual-os/sdk/Action" as const;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @since 0.0.0
|
|
35
|
+
* @category type ids
|
|
36
|
+
*/
|
|
37
|
+
export type TypeId = typeof TypeId;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Constraint type for working with any {@link Action}.
|
|
41
|
+
*
|
|
42
|
+
* @since 0.0.0
|
|
43
|
+
* @category type-level
|
|
44
|
+
*/
|
|
45
|
+
export interface Any extends Pipeable.Pipeable {
|
|
46
|
+
readonly [TypeId]: TypeId;
|
|
47
|
+
readonly identifier: string;
|
|
48
|
+
readonly name: string | undefined;
|
|
49
|
+
readonly description: string | undefined;
|
|
50
|
+
readonly input: Schema.Top;
|
|
51
|
+
readonly output: Schema.Top;
|
|
52
|
+
readonly examples: readonly ActionExample<unknown>[];
|
|
53
|
+
readonly requireAuth: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Stable action metadata.
|
|
58
|
+
*
|
|
59
|
+
* @since 0.0.0
|
|
60
|
+
* @category models
|
|
61
|
+
*/
|
|
62
|
+
export interface ActionOptions {
|
|
63
|
+
readonly name?: string | undefined;
|
|
64
|
+
readonly description?: string | undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Example input shown alongside an action definition.
|
|
69
|
+
*
|
|
70
|
+
* @since 0.0.0
|
|
71
|
+
* @category models
|
|
72
|
+
*/
|
|
73
|
+
export interface ActionExample<Input> {
|
|
74
|
+
readonly title?: string;
|
|
75
|
+
readonly input: Input;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handler context exposed to an action implementation.
|
|
80
|
+
*
|
|
81
|
+
* @since 0.0.0
|
|
82
|
+
* @category models
|
|
83
|
+
*/
|
|
84
|
+
export type HandlerContext<EffectiveAuthMethods extends readonly AuthMethod.Any[]> =
|
|
85
|
+
ContextForMethods<EffectiveAuthMethods>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Non-retryable failure reported by a trusted action handler.
|
|
89
|
+
*
|
|
90
|
+
* The invoke boundary owns action/provider/version metadata, so handler errors
|
|
91
|
+
* intentionally describe only the failed operation itself.
|
|
92
|
+
*
|
|
93
|
+
* @since 0.0.0
|
|
94
|
+
* @category errors
|
|
95
|
+
*/
|
|
96
|
+
export class ActionHandlerError extends Schema.TaggedError<ActionHandlerError>()(
|
|
97
|
+
"ActionHandlerError",
|
|
98
|
+
{
|
|
99
|
+
cause: Schema.optional(Schema.Defect()),
|
|
100
|
+
details: Schema.optional(Schema.Unknown),
|
|
101
|
+
message: Schema.String,
|
|
102
|
+
status: Schema.optional(Schema.Number),
|
|
103
|
+
},
|
|
104
|
+
) {}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Retryable failure reported by a trusted action handler.
|
|
108
|
+
*
|
|
109
|
+
* @since 0.0.0
|
|
110
|
+
* @category errors
|
|
111
|
+
*/
|
|
112
|
+
export class RetryableActionHandlerError extends Schema.TaggedError<RetryableActionHandlerError>()(
|
|
113
|
+
"RetryableActionHandlerError",
|
|
114
|
+
{
|
|
115
|
+
cause: Schema.optional(Schema.Defect()),
|
|
116
|
+
details: Schema.optional(Schema.Unknown),
|
|
117
|
+
message: Schema.String,
|
|
118
|
+
retryAfterSeconds: Schema.optional(Schema.Number),
|
|
119
|
+
status: Schema.optional(Schema.Number),
|
|
120
|
+
},
|
|
121
|
+
) {}
|
|
122
|
+
|
|
123
|
+
/** @since 0.0.0 @category errors */
|
|
124
|
+
export type ActionHandlerFailure = ActionHandlerError | RetryableActionHandlerError;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Failures produced while an Effect HTTP client executes or decodes a request.
|
|
128
|
+
*
|
|
129
|
+
* @since 0.0.0
|
|
130
|
+
* @category errors
|
|
131
|
+
*/
|
|
132
|
+
export type HttpClientFailure = HttpClientError.HttpClientError | Schema.SchemaError;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* A response the provider declared as an error, as a generated client raises it:
|
|
136
|
+
* the received response plus its decoded body.
|
|
137
|
+
*
|
|
138
|
+
* @since 0.0.0
|
|
139
|
+
* @category errors
|
|
140
|
+
*/
|
|
141
|
+
export interface DeclaredResponseFailure {
|
|
142
|
+
readonly response: { readonly status: number; readonly headers: Headers.Headers };
|
|
143
|
+
readonly cause: unknown;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function retryAfterSeconds(headers?: Headers.Headers) {
|
|
147
|
+
return pipe(
|
|
148
|
+
Option.fromNullishOr(headers),
|
|
149
|
+
Option.flatMap(Headers.get("retry-after")),
|
|
150
|
+
Option.flatMap(value =>
|
|
151
|
+
Option.orElse(Number.parse(value), () =>
|
|
152
|
+
Option.map(DateTime.make(value), date =>
|
|
153
|
+
Duration.toSeconds(DateTime.distance(DateTime.nowUnsafe(), date)),
|
|
154
|
+
),
|
|
155
|
+
),
|
|
156
|
+
),
|
|
157
|
+
Option.map(Number.clamp({ maximum: 3600, minimum: 0 })),
|
|
158
|
+
Option.getOrUndefined,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface SchemaIssueAt {
|
|
163
|
+
readonly kind: string;
|
|
164
|
+
readonly path: ReadonlyArray<PropertyKey>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Where a response broke its schema and how, as issue tags only. Effect's formatters can quote
|
|
168
|
+
// the received value, such as an unmatched union member, and failure details are stored with
|
|
169
|
+
// the run, so the provider's data stays out of them.
|
|
170
|
+
function schemaIssuesAt(
|
|
171
|
+
issue: SchemaIssue.Issue,
|
|
172
|
+
path: ReadonlyArray<PropertyKey>,
|
|
173
|
+
): Array<SchemaIssueAt> {
|
|
174
|
+
return pipe(
|
|
175
|
+
Match.value(issue),
|
|
176
|
+
Match.tags({
|
|
177
|
+
AnyOf: anyOf =>
|
|
178
|
+
Array.match(anyOf.issues, {
|
|
179
|
+
onEmpty: () => [{ kind: anyOf._tag, path }],
|
|
180
|
+
onNonEmpty: issues => Array.flatMap(issues, inner => schemaIssuesAt(inner, path)),
|
|
181
|
+
}),
|
|
182
|
+
Composite: composite => Array.flatMap(composite.issues, inner => schemaIssuesAt(inner, path)),
|
|
183
|
+
Encoding: encoding => schemaIssuesAt(encoding.issue, path),
|
|
184
|
+
Pointer: pointer => schemaIssuesAt(pointer.issue, [...path, ...pointer.path]),
|
|
185
|
+
}),
|
|
186
|
+
Match.orElse(leaf => [{ kind: leaf._tag, path }]),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function schemaIssues(issue: SchemaIssue.Issue) {
|
|
191
|
+
return Array.map(schemaIssuesAt(issue, []), located => ({
|
|
192
|
+
kind: located.kind,
|
|
193
|
+
path: Array.filter(located.path, Predicate.or(Predicate.isString, Predicate.isNumber)),
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Map an Effect HTTP client failure to the action failure contract.
|
|
199
|
+
*
|
|
200
|
+
* Transport failures, rate limits, and server errors can be retried, carrying
|
|
201
|
+
* the provider's Retry-After delay (at most an hour) when the response sent
|
|
202
|
+
* one. Request construction, response decoding, declared client errors, and
|
|
203
|
+
* other client errors are terminal.
|
|
204
|
+
*
|
|
205
|
+
* @since 0.0.0
|
|
206
|
+
* @category errors
|
|
207
|
+
*/
|
|
208
|
+
export const fromHttpClientFailure = (
|
|
209
|
+
error: HttpClientFailure | DeclaredResponseFailure,
|
|
210
|
+
): ActionHandlerFailure => {
|
|
211
|
+
if (Schema.isSchemaError(error)) {
|
|
212
|
+
return new ActionHandlerError({
|
|
213
|
+
cause: error,
|
|
214
|
+
details: { issues: schemaIssues(error.issue), reason: "SchemaError" },
|
|
215
|
+
message: "HTTP response did not match the expected schema",
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (!HttpClientError.isHttpClientError(error)) {
|
|
219
|
+
const status = error.response.status;
|
|
220
|
+
const fields = {
|
|
221
|
+
details: error.cause,
|
|
222
|
+
message: `HTTP request failed with status ${status}`,
|
|
223
|
+
status,
|
|
224
|
+
};
|
|
225
|
+
return status === 429 || status >= 500
|
|
226
|
+
? RetryableActionHandlerError.make({
|
|
227
|
+
...fields,
|
|
228
|
+
retryAfterSeconds: retryAfterSeconds(error.response.headers),
|
|
229
|
+
})
|
|
230
|
+
: new ActionHandlerError(fields);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const status = error.response?.status;
|
|
234
|
+
const fields = {
|
|
235
|
+
message:
|
|
236
|
+
status === undefined ? "HTTP request failed" : `HTTP request failed with status ${status}`,
|
|
237
|
+
...(status === undefined ? {} : { status }),
|
|
238
|
+
details: { method: error.request.method, reason: error.reason._tag },
|
|
239
|
+
cause: error,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
return error.reason._tag === "TransportError" ||
|
|
243
|
+
status === 429 ||
|
|
244
|
+
(status !== undefined && status >= 500)
|
|
245
|
+
? RetryableActionHandlerError.make({
|
|
246
|
+
...fields,
|
|
247
|
+
retryAfterSeconds: retryAfterSeconds(error.response?.headers),
|
|
248
|
+
})
|
|
249
|
+
: new ActionHandlerError(fields);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Map an Effect HTTP client effect onto the action failure contract.
|
|
254
|
+
*
|
|
255
|
+
* @since 0.0.0
|
|
256
|
+
* @category errors
|
|
257
|
+
*/
|
|
258
|
+
export const orHttpClientFailure = <A, R>(
|
|
259
|
+
effect: Effect.Effect<A, HttpClientFailure | DeclaredResponseFailure, R>,
|
|
260
|
+
): Effect.Effect<A, ActionHandlerFailure, R> => Effect.mapError(effect, fromHttpClientFailure);
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* A runtime handler service for one canonical action id.
|
|
264
|
+
*
|
|
265
|
+
* @since 0.0.0
|
|
266
|
+
* @category models
|
|
267
|
+
*/
|
|
268
|
+
export interface Handler<ActionId extends string = string> {
|
|
269
|
+
readonly _: unique symbol;
|
|
270
|
+
readonly actionId: ActionId;
|
|
271
|
+
readonly context: Context.Context<never>;
|
|
272
|
+
readonly handler: (
|
|
273
|
+
input: unknown,
|
|
274
|
+
context: unknown,
|
|
275
|
+
) => Effect.Effect<unknown, ActionHandlerFailure, unknown>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Context key used for the action handler with the supplied canonical id.
|
|
280
|
+
*
|
|
281
|
+
* @since 0.0.0
|
|
282
|
+
* @category handlers
|
|
283
|
+
*/
|
|
284
|
+
export const handlerKey = (actionId: string): string => `@dual-os/sdk/Action/Handler/${actionId}`;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Options used to declare an action contract.
|
|
288
|
+
*
|
|
289
|
+
* @since 0.6.0
|
|
290
|
+
* @category models
|
|
291
|
+
*/
|
|
292
|
+
export interface ContractOptions<
|
|
293
|
+
Input extends Schema.Top,
|
|
294
|
+
Output extends Schema.Top,
|
|
295
|
+
RequireAuth extends boolean,
|
|
296
|
+
> extends ActionOptions {
|
|
297
|
+
readonly input: Input;
|
|
298
|
+
readonly output: Output;
|
|
299
|
+
readonly examples?: readonly ActionExample<Schema.Schema.Type<Input>>[];
|
|
300
|
+
/** Set to `false` to make a connection optional for this action. */
|
|
301
|
+
readonly requireAuth?: RequireAuth;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* A typed action declaration.
|
|
306
|
+
*
|
|
307
|
+
* @since 0.0.0
|
|
308
|
+
* @category models
|
|
309
|
+
*/
|
|
310
|
+
export interface Action<
|
|
311
|
+
out Identifier extends string = string,
|
|
312
|
+
out Input extends Schema.Top = Schema.Top,
|
|
313
|
+
out Output extends Schema.Top = Schema.Top,
|
|
314
|
+
out RequireAuth extends boolean = boolean,
|
|
315
|
+
>
|
|
316
|
+
extends Pipeable.Pipeable {
|
|
317
|
+
readonly [TypeId]: TypeId;
|
|
318
|
+
readonly identifier: Identifier;
|
|
319
|
+
readonly name: string | undefined;
|
|
320
|
+
readonly description: string | undefined;
|
|
321
|
+
readonly input: Input;
|
|
322
|
+
readonly output: Output;
|
|
323
|
+
readonly examples: readonly ActionExample<Schema.Schema.Type<Input>>[];
|
|
324
|
+
readonly requireAuth: RequireAuth;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export type InputSchema<ActionDef extends Any> = ActionDef["input"];
|
|
328
|
+
|
|
329
|
+
export type OutputSchema<ActionDef extends Any> = ActionDef["output"];
|
|
330
|
+
|
|
331
|
+
export type Input<ActionDef extends Any> = Schema.Schema.Type<InputSchema<ActionDef>>;
|
|
332
|
+
|
|
333
|
+
export type Output<ActionDef extends Any> = Schema.Schema.Type<OutputSchema<ActionDef>>;
|
|
334
|
+
|
|
335
|
+
const Proto = { ...PipeableProto, [TypeId]: TypeId };
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Create an {@link Action} from its contract.
|
|
339
|
+
*
|
|
340
|
+
* @since 0.0.0
|
|
341
|
+
* @category constructors
|
|
342
|
+
*/
|
|
343
|
+
export const make = <
|
|
344
|
+
const Identifier extends string,
|
|
345
|
+
Input extends Schema.Top,
|
|
346
|
+
Output extends Schema.Top,
|
|
347
|
+
const RequireAuth extends boolean = true,
|
|
348
|
+
>(
|
|
349
|
+
identifier: Identifier,
|
|
350
|
+
options: ContractOptions<Input, Output, RequireAuth>,
|
|
351
|
+
): Action<Identifier, Input, Output, RequireAuth> => {
|
|
352
|
+
validateIdentifier("action", identifier);
|
|
353
|
+
return Object.assign(Object.create(Proto), {
|
|
354
|
+
description: options.description,
|
|
355
|
+
examples: options.examples ?? [],
|
|
356
|
+
identifier,
|
|
357
|
+
input: options.input,
|
|
358
|
+
name: options.name,
|
|
359
|
+
output: options.output,
|
|
360
|
+
requireAuth: options.requireAuth ?? true,
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Check if a value is an {@link Action}.
|
|
366
|
+
*
|
|
367
|
+
* @since 0.0.0
|
|
368
|
+
* @category guards
|
|
369
|
+
*/
|
|
370
|
+
export const isAction = (u: unknown): u is Any => Predicate.hasProperty(u, TypeId);
|