@pikku/core 0.12.91 → 0.12.93
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/CHANGELOG.md +102 -0
- package/dist/errors/error-handler.d.ts +11 -0
- package/dist/errors/error-handler.js +8 -0
- package/dist/errors/serialized-error.d.ts +3 -0
- package/dist/function/function-runner.d.ts +1 -1
- package/dist/function/function-runner.js +3 -3
- package/dist/function/functions.types.d.ts +33 -21
- package/dist/middleware/auth-apikey.d.ts +7 -0
- package/dist/middleware/auth-apikey.js +6 -0
- package/dist/middleware/auth-bearer.d.ts +3 -0
- package/dist/middleware/auth-bearer.js +2 -0
- package/dist/middleware/auth-cookie.d.ts +9 -0
- package/dist/middleware/auth-cookie.js +6 -4
- package/dist/middleware/cors.d.ts +8 -0
- package/dist/middleware/cors.js +2 -0
- package/dist/middleware/middleware-factories.d.ts +14 -0
- package/dist/middleware/middleware-factories.js +14 -0
- package/dist/services/local-secrets.js +1 -1
- package/dist/services/persona-sign-in.d.ts +0 -2
- package/dist/services/persona-sign-in.js +15 -66
- package/dist/services/personas-service.d.ts +4 -0
- package/dist/services/personas-service.js +4 -0
- package/dist/services/secret-service.d.ts +0 -1
- package/dist/testing/service-tests/secret-service-tests.js +1 -1
- package/dist/types/core.types.d.ts +5 -0
- package/dist/wirings/addon/wire-addon.d.ts +17 -15
- package/dist/wirings/addon/wire-addon.js +6 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +4 -0
- package/dist/wirings/addon/wire-remote-addon.js +4 -0
- package/dist/wirings/agent/agent-prepare.js +2 -2
- package/dist/wirings/agent/agent.types.d.ts +31 -27
- package/dist/wirings/agent-scorer/agent-scorer.d.ts +4 -0
- package/dist/wirings/agent-scorer/agent-scorer.js +4 -0
- package/dist/wirings/channel/channel.types.d.ts +11 -0
- package/dist/wirings/cli/cli.types.d.ts +43 -1
- package/dist/wirings/cli/define-cli-commands.d.ts +6 -1
- package/dist/wirings/cli/define-cli-commands.js +6 -1
- package/dist/wirings/credential/credential.types.d.ts +7 -0
- package/dist/wirings/gateway/gateway.types.d.ts +23 -0
- package/dist/wirings/http/http.types.d.ts +51 -37
- package/dist/wirings/mcp/mcp.types.d.ts +27 -0
- package/dist/wirings/queue/queue.types.d.ts +6 -0
- package/dist/wirings/scheduler/scheduler.types.d.ts +5 -0
- package/dist/wirings/secret/secret.types.d.ts +9 -14
- package/dist/wirings/secret/secret.types.js +7 -0
- package/dist/wirings/trigger/trigger.types.d.ts +4 -1
- package/dist/wirings/variable/variable.types.d.ts +14 -13
- package/dist/wirings/variable/variable.types.js +7 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +7 -0
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +6 -0
- package/dist/wirings/workflow/scenario-cookie-jar.js +6 -0
- package/dist/wirings/workflow/scenario-poll.d.ts +6 -0
- package/dist/wirings/workflow/scenario-poll.js +6 -0
- package/dist/wirings/workflow/scenario-step-guards.d.ts +6 -0
- package/dist/wirings/workflow/scenario-step-guards.js +6 -0
- package/dist/wirings/workflow/workflow-errors.d.ts +4 -0
- package/dist/wirings/workflow/workflow-errors.js +4 -0
- package/package.json +1 -1
- package/src/app-leaf-surface.test.ts +2 -2
- package/src/errors/error-handler.ts +11 -0
- package/src/errors/serialized-error.ts +3 -0
- package/src/function/function-runner.ts +4 -4
- package/src/function/functions.types.ts +33 -21
- package/src/middleware/auth-apikey.ts +7 -0
- package/src/middleware/auth-bearer.ts +3 -0
- package/src/middleware/auth-cookie.ts +9 -4
- package/src/middleware/cors.ts +8 -0
- package/src/middleware/middleware-factories.ts +14 -0
- package/src/services/local-secrets.test.ts +2 -2
- package/src/services/local-secrets.ts +1 -1
- package/src/services/persona-sign-in.test.ts +28 -34
- package/src/services/persona-sign-in.ts +16 -88
- package/src/services/personas-service.ts +4 -0
- package/src/services/secret-service.ts +0 -1
- package/src/testing/service-tests/secret-service-tests.ts +1 -1
- package/src/types/core.types.ts +5 -0
- package/src/wirings/addon/addon-auth-tags.test.ts +4 -4
- package/src/wirings/addon/wire-addon.ts +17 -15
- package/src/wirings/addon/wire-remote-addon.ts +4 -0
- package/src/wirings/agent/agent-authorization.test.ts +7 -3
- package/src/wirings/agent/agent-prepare.ts +2 -2
- package/src/wirings/agent/agent.types.ts +31 -27
- package/src/wirings/agent-scorer/agent-scorer.ts +4 -0
- package/src/wirings/channel/channel.types.ts +11 -0
- package/src/wirings/cli/cli.types.ts +44 -1
- package/src/wirings/cli/define-cli-commands.ts +6 -1
- package/src/wirings/credential/credential.types.ts +7 -0
- package/src/wirings/gateway/gateway-authorization.test.ts +3 -3
- package/src/wirings/gateway/gateway.types.ts +23 -0
- package/src/wirings/http/http-runner-addon-ref.test.ts +1 -1
- package/src/wirings/http/http.types.ts +94 -69
- package/src/wirings/mcp/mcp.types.ts +27 -0
- package/src/wirings/queue/queue.types.ts +6 -0
- package/src/wirings/scheduler/scheduler.types.ts +5 -0
- package/src/wirings/secret/secret.types.ts +9 -14
- package/src/wirings/trigger/trigger.types.ts +4 -1
- package/src/wirings/variable/variable.types.ts +14 -13
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
- package/src/wirings/workflow/scenario-cookie-jar.ts +6 -0
- package/src/wirings/workflow/scenario-poll.ts +6 -0
- package/src/wirings/workflow/scenario-step-guards.ts +6 -0
- package/src/wirings/workflow/workflow-errors.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -26,14 +26,18 @@ export type RunHTTPWiringOptions = Partial<{
|
|
|
26
26
|
export type HTTPMethod = 'post' | 'get' | 'delete' | 'patch' | 'head' | 'put' | 'options';
|
|
27
27
|
export type HTTPHeadersSchema = StandardSchemaV1<Record<string, string | string[] | undefined>>;
|
|
28
28
|
export type HTTPRouteBaseConfig = {
|
|
29
|
+
/** How the body is serialised. Defaults to JSON; `xml` is for routes a caller you do not control insists on. */
|
|
29
30
|
contentType?: 'xml' | 'json';
|
|
31
|
+
/** Seconds before the request is abandoned. Work that can outlast a request should be dispatched instead, not given a longer timeout. */
|
|
30
32
|
timeout?: number;
|
|
33
|
+
/** Filters this route in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
31
34
|
tags?: string[];
|
|
35
|
+
/** A schema the request headers are validated against, so a missing or malformed header fails before the function body runs. */
|
|
32
36
|
headers?: HTTPHeadersSchema;
|
|
33
37
|
};
|
|
34
38
|
export type CoreHTTPFunction = HTTPRouteBaseConfig & {
|
|
35
39
|
route: string;
|
|
36
|
-
|
|
40
|
+
/** Sends the returned value as-is rather than JSON-encoding it, for a route whose body is binary or already serialised. */
|
|
37
41
|
returnsJSON?: false;
|
|
38
42
|
};
|
|
39
43
|
export interface PikkuHTTP<In = unknown> {
|
|
@@ -41,51 +45,61 @@ export interface PikkuHTTP<In = unknown> {
|
|
|
41
45
|
response?: PikkuHTTPResponse;
|
|
42
46
|
}
|
|
43
47
|
export type PikkuQuery<T = Record<string, string | undefined>> = Record<string, string | T | null | Array<T | null>>;
|
|
44
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The keys every HTTP wiring takes, whatever it is wired to. The three that
|
|
50
|
+
* are not here — `method`, `auth` and `func` — are correlated rather than
|
|
51
|
+
* independent, and live in the unions below.
|
|
52
|
+
*/
|
|
53
|
+
type HTTPWiringShared<R extends string, PikkuMiddleware extends CorePikkuMiddleware<any, any>> = CoreHTTPFunction & {
|
|
54
|
+
/**
|
|
55
|
+
* The path this wiring answers on. `:name` marks a parameter, and every
|
|
56
|
+
* parameter in the path must be a key of the function's input schema —
|
|
57
|
+
* a mismatch is a compile error rather than a 404 at runtime.
|
|
58
|
+
*/
|
|
45
59
|
route: R;
|
|
46
|
-
|
|
47
|
-
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
48
|
-
auth?: true;
|
|
60
|
+
/** Wraps every request to this route: auth, tracing, rate limiting. Runs before the permissions on `func`. */
|
|
49
61
|
middleware?: PikkuMiddleware[];
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* `auth` decides which kind of function this route can point at, so the two
|
|
65
|
+
* travel together: a route that requires a session gets a function that is
|
|
66
|
+
* handed one, and an open route gets a sessionless function that has none to
|
|
67
|
+
* read. Splitting them would let a function ask for a session the route never
|
|
68
|
+
* establishes.
|
|
69
|
+
*/
|
|
70
|
+
type HTTPWiringAuth<In, Out, PikkuFunction extends CorePikkuFunction<In, Out, any, any, any>, PikkuFunctionSessionless extends CorePikkuFunctionSessionless<In, Out, any, any, any>, PikkuPermission extends CorePikkuPermission<In, any, any>, PikkuMiddleware extends CorePikkuMiddleware<any, any>> = {
|
|
71
|
+
/** Whether reaching this route requires a session. Defaults to true — a route is closed unless it says otherwise. */
|
|
72
|
+
auth?: true;
|
|
73
|
+
/** The function to run. It is handed the session this route required. */
|
|
74
|
+
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
75
|
+
} | {
|
|
76
|
+
/** Whether reaching this route requires a session. Defaults to true — a route is closed unless it says otherwise. */
|
|
55
77
|
auth?: false;
|
|
56
|
-
|
|
78
|
+
/** On an open route there is no session, so this must be a sessionless function. */
|
|
79
|
+
func: CorePikkuFunctionConfig<PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* `sse` and `query` are each valid on one method only, so the method carries
|
|
83
|
+
* them: streaming is a GET, and naming which input keys arrive in the query
|
|
84
|
+
* string is only a question on a POST, where the rest of the input is a body.
|
|
85
|
+
*/
|
|
86
|
+
type HTTPWiringMethod<In> = {
|
|
87
|
+
/** The HTTP method. A route and method together address one wiring. */
|
|
88
|
+
method: HTTPMethod;
|
|
57
89
|
sse?: undefined;
|
|
58
|
-
}
|
|
59
|
-
route
|
|
60
|
-
method: 'get';
|
|
61
|
-
func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>;
|
|
62
|
-
auth?: true;
|
|
63
|
-
middleware?: PikkuMiddleware[];
|
|
64
|
-
sse?: boolean;
|
|
65
|
-
}) | (CoreHTTPFunction & {
|
|
66
|
-
route: R;
|
|
90
|
+
} | {
|
|
91
|
+
/** The HTTP method. A route and method together address one wiring. */
|
|
67
92
|
method: 'get';
|
|
68
|
-
|
|
69
|
-
auth?: false;
|
|
70
|
-
middleware?: PikkuMiddleware[];
|
|
93
|
+
/** Streams the response as server-sent events instead of returning it once. GET only. */
|
|
71
94
|
sse?: boolean;
|
|
72
|
-
}
|
|
73
|
-
route
|
|
95
|
+
} | {
|
|
96
|
+
/** The HTTP method. A route and method together address one wiring. */
|
|
74
97
|
method: 'post';
|
|
75
|
-
|
|
76
|
-
auth?: true;
|
|
77
|
-
middleware?: PikkuMiddleware[];
|
|
98
|
+
/** Input keys that arrive in the query string rather than the body. POST only, where the body is the default home for input. */
|
|
78
99
|
query?: Array<keyof In>;
|
|
79
100
|
sse?: undefined;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
method: 'post';
|
|
83
|
-
func: CorePikkuFunctionConfig<PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>;
|
|
84
|
-
auth?: false;
|
|
85
|
-
middleware?: PikkuMiddleware[];
|
|
86
|
-
query?: Array<keyof In>;
|
|
87
|
-
sse?: undefined;
|
|
88
|
-
});
|
|
101
|
+
};
|
|
102
|
+
export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction extends CorePikkuFunction<In, Out, any, any, any> = CorePikkuFunction<In, Out>, PikkuFunctionSessionless extends CorePikkuFunctionSessionless<In, Out, any, any, any> = CorePikkuFunctionSessionless<In, Out>, PikkuPermission extends CorePikkuPermission<In, any, any> = CorePikkuPermission<In, any, any>, PikkuMiddleware extends CorePikkuMiddleware<any, any> = CorePikkuMiddleware<any, any>> = HTTPWiringShared<R, PikkuMiddleware> & HTTPWiringAuth<In, Out, PikkuFunction, PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware> & HTTPWiringMethod<In>;
|
|
89
103
|
export type HTTPFunctionMetaInputTypes = {
|
|
90
104
|
params?: string;
|
|
91
105
|
query?: string;
|
|
@@ -40,36 +40,63 @@ export type MCPPromptMeta = Record<string, Omit<CoreMCPPrompt, 'func' | 'middlew
|
|
|
40
40
|
middleware?: MiddlewareMetadata[];
|
|
41
41
|
}>;
|
|
42
42
|
export type CoreMCPResource<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, any>>, PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>> = {
|
|
43
|
+
/** How the client addresses this resource. `{name}` marks a parameter, and every parameter must be a key of the function's input schema. */
|
|
43
44
|
uri: string;
|
|
45
|
+
/** The name a human sees in a client's resource list. */
|
|
44
46
|
title: string;
|
|
47
|
+
/** What the resource holds, written for the model deciding whether to read it. */
|
|
45
48
|
description: string;
|
|
49
|
+
/** A one-line description for listings, where the full `description` is too long. */
|
|
46
50
|
summary?: string;
|
|
51
|
+
/** Names of error classes this may throw, so the client is told which failures are its own fault. */
|
|
47
52
|
errors?: string[];
|
|
53
|
+
/** The media type of what the function returns, so the client knows whether it is text, JSON or an image. */
|
|
48
54
|
mimeType?: string;
|
|
55
|
+
/** Size in bytes, where it is known ahead of the read. A client uses it to decide whether to fetch at all. */
|
|
49
56
|
size?: number;
|
|
57
|
+
/** Whether the function returns the content in chunks rather than at once. */
|
|
50
58
|
streaming?: boolean;
|
|
59
|
+
/** The function to run. It is sessionless: an MCP client is not a logged-in user. */
|
|
51
60
|
func: PikkuFunctionConfig;
|
|
61
|
+
/** Filters this wiring in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
52
62
|
tags?: string[];
|
|
63
|
+
/** Wraps every call: tracing, rate limiting, whatever the transport does not do. */
|
|
53
64
|
middleware?: PikkuMiddleware[];
|
|
54
65
|
};
|
|
55
66
|
export type CoreMCPTool<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, any>>, PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>> = {
|
|
67
|
+
/** How the model calls this tool. It is the tool's identity, so renaming it breaks any client that already knows it. */
|
|
56
68
|
name: string;
|
|
69
|
+
/** The name a human sees, where the calling `name` is not readable. */
|
|
57
70
|
title?: string;
|
|
71
|
+
/** What the tool does and when to reach for it. This is what the model decides on, so it earns more care than the rest of this object. */
|
|
58
72
|
description?: string;
|
|
73
|
+
/** A one-line description for listings, where the full `description` is too long. */
|
|
59
74
|
summary?: string;
|
|
75
|
+
/** Names of error classes this may throw, so the client is told which failures are its own fault. */
|
|
60
76
|
errors?: string[];
|
|
77
|
+
/** The function to run. It is sessionless: an MCP client is not a logged-in user. */
|
|
61
78
|
func: PikkuFunctionConfig;
|
|
79
|
+
/** Filters this wiring in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
62
80
|
tags?: string[];
|
|
81
|
+
/** Whether the function returns its result in chunks rather than at once. */
|
|
63
82
|
streaming?: boolean;
|
|
83
|
+
/** Wraps every call: tracing, rate limiting, whatever the transport does not do. */
|
|
64
84
|
middleware?: PikkuMiddleware[];
|
|
65
85
|
};
|
|
66
86
|
export type CoreMCPPrompt<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, MCPPromptResponse>>, PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>> = {
|
|
87
|
+
/** How the client asks for this prompt. */
|
|
67
88
|
name: string;
|
|
89
|
+
/** What the prompt is for, written for the human picking it out of a list. */
|
|
68
90
|
description: string;
|
|
91
|
+
/** A one-line description for listings, where the full `description` is too long. */
|
|
69
92
|
summary?: string;
|
|
93
|
+
/** Names of error classes this may throw, so the client is told which failures are its own fault. */
|
|
70
94
|
errors?: string[];
|
|
95
|
+
/** The function to run. It is sessionless: an MCP client is not a logged-in user. */
|
|
71
96
|
func: PikkuFunctionConfig;
|
|
97
|
+
/** Filters this wiring in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
72
98
|
tags?: string[];
|
|
99
|
+
/** Wraps every call: tracing, rate limiting, whatever the transport does not do. */
|
|
73
100
|
middleware?: PikkuMiddleware[];
|
|
74
101
|
};
|
|
75
102
|
export type JsonRpcRequest = {
|
|
@@ -110,11 +110,17 @@ export type QueueWorkersMeta = Record<string, CommonWireMeta & {
|
|
|
110
110
|
config?: PikkuWorkerConfig;
|
|
111
111
|
}>;
|
|
112
112
|
export type CoreQueueWorker<PikkuFunctionConfig extends CorePikkuFunctionConfig<any, any, any> = CorePikkuFunctionConfig<any, any, any>> = {
|
|
113
|
+
/** The queue this worker consumes. Whoever enqueues a job names the same string, so it is the contract between producer and consumer. */
|
|
113
114
|
name: string;
|
|
115
|
+
/** The function to run per job. Its `input` schema is the job payload's schema — a job that does not match is rejected before the body runs. */
|
|
114
116
|
func: PikkuFunctionConfig;
|
|
117
|
+
/** Concurrency, retry and backoff, passed through to the queue service backing this worker. Defaults come from the service, not from here. */
|
|
115
118
|
config?: PikkuWorkerConfig;
|
|
119
|
+
/** Names of error classes that mean the job is bad rather than the run — thrown, they fail the job permanently instead of being retried. */
|
|
116
120
|
errors?: string[];
|
|
121
|
+
/** Filters this worker in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
117
122
|
tags?: string[];
|
|
123
|
+
/** Wraps every job. There is no request to read from, so this is for tracing, locking and teardown rather than auth. */
|
|
118
124
|
middleware?: PikkuFunctionConfig['middleware'];
|
|
119
125
|
};
|
|
120
126
|
export interface PikkuQueue {
|
|
@@ -7,10 +7,15 @@ export type ScheduledTasksMeta<UserSession extends CoreUserSession = any> = Reco
|
|
|
7
7
|
session?: UserSession;
|
|
8
8
|
}>;
|
|
9
9
|
export type CoreScheduledTask<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<void, void>>, PikkuMiddleware = CorePikkuMiddleware<any>> = {
|
|
10
|
+
/** Unique across the project. It is how the task is addressed in logs, in `pikku meta`, and by a scheduler service asked to run it now. */
|
|
10
11
|
name: string;
|
|
12
|
+
/** A five-field cron expression: minute, hour, day of month, month, day of week. `0 9 * * 1` is 09:00 every Monday. Interpreted in the deployment's timezone, not the author's. */
|
|
11
13
|
schedule: string;
|
|
14
|
+
/** The function to run. It receives no session and no input: a scheduled task has no caller, so it must be sessionless. */
|
|
12
15
|
func: PikkuFunctionConfig;
|
|
16
|
+
/** Filters this task in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
13
17
|
tags?: string[];
|
|
18
|
+
/** Wraps every execution. There is no request to read from, so this is for tracing, locking and teardown rather than auth. */
|
|
14
19
|
middleware?: PikkuMiddleware[];
|
|
15
20
|
};
|
|
16
21
|
export interface PikkuScheduledTask {
|
|
@@ -4,21 +4,9 @@ export type CoreSecret<T = unknown> = {
|
|
|
4
4
|
description?: string;
|
|
5
5
|
secretId: string;
|
|
6
6
|
schema: T;
|
|
7
|
-
/**
|
|
8
|
-
* A secret is REQUIRED by default because `getSecret` throws when the value is
|
|
9
|
-
* missing — a deploy without it is a runtime failure waiting to happen, so the
|
|
10
|
-
* deploy gate refuses it. Mark a secret `optional` when absence is a supported
|
|
11
|
-
* state the app handles (a feature that simply stays off): the generated map
|
|
12
|
-
* emits it as an optional property and `getSecret` resolves `undefined`
|
|
13
|
-
* instead of throwing.
|
|
14
|
-
*/
|
|
7
|
+
/** Required by default: this says absence is a supported state, and `getSecret` resolves `undefined` rather than throwing. */
|
|
15
8
|
optional?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Where a user goes to obtain this value — a provider's API-key page, a setup
|
|
18
|
-
* guide, an internal runbook. Consoles and deploy UIs surface it beside a
|
|
19
|
-
* missing value. The same field on every credential/variable definition means
|
|
20
|
-
* the same thing.
|
|
21
|
-
*/
|
|
9
|
+
/** Where a user goes to obtain this value, surfaced beside a missing one. */
|
|
22
10
|
docsUrl?: string;
|
|
23
11
|
/** Rotation cadence as a duration string, e.g. `'1d'`, `'30day'`, `'1w'`. */
|
|
24
12
|
rotationPeriod?: string;
|
|
@@ -59,4 +47,11 @@ export type SecretDefinitionMeta = {
|
|
|
59
47
|
};
|
|
60
48
|
export type SecretDefinitionsMeta = Record<string, SecretDefinitionMeta>;
|
|
61
49
|
export type SecretDefinitions = SecretDefinitionMeta[];
|
|
50
|
+
/**
|
|
51
|
+
* Declares a secret this project needs, with the shape of its value. The CLI
|
|
52
|
+
* collects every declaration into `CredentialsMap`, which is what makes
|
|
53
|
+
* `secrets.getSecret('NAME')` return the right type instead of `unknown`.
|
|
54
|
+
*
|
|
55
|
+
* @example snippet: secrets
|
|
56
|
+
*/
|
|
62
57
|
export declare const defineSecret: <T>(_config: CoreSecret<T>) => void;
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declares a secret this project needs, with the shape of its value. The CLI
|
|
3
|
+
* collects every declaration into `CredentialsMap`, which is what makes
|
|
4
|
+
* `secrets.getSecret('NAME')` return the right type instead of `unknown`.
|
|
5
|
+
*
|
|
6
|
+
* @example snippet: secrets
|
|
7
|
+
*/
|
|
1
8
|
export const defineSecret = (_config) => { };
|
|
@@ -28,11 +28,14 @@ export type CorePikkuTriggerFunctionConfig<TInput = unknown, TOutput = unknown,
|
|
|
28
28
|
};
|
|
29
29
|
export declare const pikkuTriggerFunc: <TInput = unknown, TOutput = unknown, Services extends CoreSingletonServices = CoreSingletonServices, InputSchema extends StandardSchemaV1 | undefined = undefined, OutputSchema extends StandardSchemaV1 | undefined = undefined>(triggerOrConfig: CorePikkuTriggerFunction<TInput, TOutput, Services> | CorePikkuTriggerFunctionConfig<TInput, TOutput, Services, InputSchema, OutputSchema>) => CorePikkuTriggerFunctionConfig<TInput, TOutput, Services, InputSchema, OutputSchema>;
|
|
30
30
|
export interface CoreTrigger<PikkuFunctionConfig = any> {
|
|
31
|
+
/** What a `wireTriggerSource` points at to fire this trigger. It is the contract between the two, so both must spell it the same. */
|
|
31
32
|
name: string;
|
|
33
|
+
/** The function to run each time the trigger fires. */
|
|
32
34
|
func: PikkuFunctionConfig;
|
|
35
|
+
/** What firing this trigger means, for whoever is reading the wiring rather than writing it. */
|
|
33
36
|
description?: string;
|
|
37
|
+
/** Filters this trigger in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
34
38
|
tags?: string[];
|
|
35
|
-
graph?: true;
|
|
36
39
|
}
|
|
37
40
|
export interface TriggerInstance {
|
|
38
41
|
name: string;
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
export type CoreVariable<T = unknown> = {
|
|
2
|
+
/** How the variable is asked for in code. Generated into `VariablesMap`, so it is what `variables.get` autocompletes. */
|
|
2
3
|
name: string;
|
|
4
|
+
/** The name shown to whoever configures the deployment. */
|
|
3
5
|
displayName: string;
|
|
6
|
+
/** What the value does, for the person setting it rather than the one reading it. */
|
|
4
7
|
description?: string;
|
|
8
|
+
/** The environment variable this reads, which is the name that has to exist on the host. */
|
|
5
9
|
variableId: string;
|
|
10
|
+
/** The shape of the value. It arrives as a string, so this is also what parses it. */
|
|
6
11
|
schema: T;
|
|
7
|
-
/**
|
|
8
|
-
* A variable is REQUIRED by default, and marking it `optional` is how a
|
|
9
|
-
* declaration says its absence is a supported state. Same flag, same
|
|
10
|
-
* polarity and same meaning as `CoreSecret.optional` — one word to learn
|
|
11
|
-
* rather than two with opposite senses.
|
|
12
|
-
*
|
|
13
|
-
* Defaulting to required rather than following `variables.get`'s
|
|
14
|
-
* `T | undefined` return is deliberate. That signature describes what a
|
|
15
|
-
* caller must HANDLE, not whether a deployment is correct without the value:
|
|
16
|
-
* an undefined feature flag is fine, an undefined API base URL is an outage
|
|
17
|
-
* that the type system cannot tell apart. Declaring the difference is the
|
|
18
|
-
* point of the flag, and the safe default for an undeclared one is to ask.
|
|
19
|
-
*/
|
|
12
|
+
/** Required by default: this says the deployment is still correct without it. */
|
|
20
13
|
optional?: boolean;
|
|
14
|
+
/** Where to go to work out what to set this to. */
|
|
21
15
|
docsUrl?: string;
|
|
22
16
|
};
|
|
23
17
|
export type VariableDefinitionMeta = {
|
|
@@ -32,4 +26,11 @@ export type VariableDefinitionMeta = {
|
|
|
32
26
|
};
|
|
33
27
|
export type VariableDefinitionsMeta = Record<string, VariableDefinitionMeta>;
|
|
34
28
|
export type VariableDefinitions = VariableDefinitionMeta[];
|
|
29
|
+
/**
|
|
30
|
+
* Declares an environment variable this project needs, with the shape of its
|
|
31
|
+
* value. The CLI collects every declaration into `VariablesMap`, which is what
|
|
32
|
+
* makes `variables.get('NAME')` return the right type instead of `unknown`.
|
|
33
|
+
*
|
|
34
|
+
* @example snippet: variables
|
|
35
|
+
*/
|
|
35
36
|
export declare const defineVariable: <T>(_config: CoreVariable<T>) => void;
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declares an environment variable this project needs, with the shape of its
|
|
3
|
+
* value. The CLI collects every declaration into `VariablesMap`, which is what
|
|
4
|
+
* makes `variables.get('NAME')` return the right type instead of `unknown`.
|
|
5
|
+
*
|
|
6
|
+
* @example snippet: variables
|
|
7
|
+
*/
|
|
1
8
|
export const defineVariable = (_config) => { };
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
export interface PikkuWorkflowGraphConfig<FuncMap extends Record<string, string>, T> {
|
|
2
|
+
/** Keeps the graph in the codebase but out of the build. */
|
|
2
3
|
disabled?: true;
|
|
4
|
+
/** Unique across the project. It is how the graph is started and how its runs are grouped. */
|
|
3
5
|
name?: string;
|
|
6
|
+
/** What the graph does, for whoever is reading it rather than editing it. */
|
|
4
7
|
description?: string;
|
|
8
|
+
/** Filters this graph in and out of a build — see the `tags` option on `pikku all`. It has no effect at runtime. */
|
|
5
9
|
tags?: string[];
|
|
10
|
+
/** The graph's steps, keyed by node id, each naming a function. `pikku meta` lists the names available here. */
|
|
6
11
|
nodes: FuncMap;
|
|
12
|
+
/** Per-node settings — retries, timeouts, the edges between them. */
|
|
7
13
|
config?: T;
|
|
14
|
+
/** Free text carried onto the rendered graph, for a reader who needs the reasoning the shape cannot show. */
|
|
8
15
|
notes?: string[];
|
|
9
16
|
}
|
|
10
17
|
export interface PikkuWorkflowGraphResult {
|
|
@@ -3,4 +3,10 @@ export interface ScenarioCookieJar {
|
|
|
3
3
|
clear(): void;
|
|
4
4
|
readonly empty: boolean;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* A cookie store for a scenario run, so a step that signs in leaves the session
|
|
8
|
+
* cookie behind for the steps after it.
|
|
9
|
+
*
|
|
10
|
+
* @example snippet: scenarioCookieJar
|
|
11
|
+
*/
|
|
6
12
|
export declare const createCookieJar: (apiUrl: string) => ScenarioCookieJar;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cookie store for a scenario run, so a step that signs in leaves the session
|
|
3
|
+
* cookie behind for the steps after it.
|
|
4
|
+
*
|
|
5
|
+
* @example snippet: scenarioCookieJar
|
|
6
|
+
*/
|
|
1
7
|
export const createCookieJar = (apiUrl) => {
|
|
2
8
|
const jar = new Map();
|
|
3
9
|
const origin = new URL(apiUrl).origin;
|
|
@@ -2,4 +2,10 @@ export interface PollOptions {
|
|
|
2
2
|
timeoutMs?: number;
|
|
3
3
|
intervalMs?: number;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Retries an assertion until it passes or the timeout runs out — for the
|
|
7
|
+
* eventually-consistent parts of a scenario (a queued job, a projection).
|
|
8
|
+
*
|
|
9
|
+
* @example snippet: scenarioPolling
|
|
10
|
+
*/
|
|
5
11
|
export declare const pollUntil: <T>(attempt: () => Promise<T | undefined> | T | undefined, { timeoutMs, intervalMs }?: PollOptions) => Promise<T | undefined>;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retries an assertion until it passes or the timeout runs out — for the
|
|
3
|
+
* eventually-consistent parts of a scenario (a queued job, a projection).
|
|
4
|
+
*
|
|
5
|
+
* @example snippet: scenarioPolling
|
|
6
|
+
*/
|
|
1
7
|
export const pollUntil = async (attempt, { timeoutMs = 15_000, intervalMs = 250 } = {}) => {
|
|
2
8
|
const deadline = Date.now() + timeoutMs;
|
|
3
9
|
for (;;) {
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import type { PikkuScenarioStepWire, ScenarioEnvironment } from './scenario-step.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The environment the current scenario run targets, or a throw explaining that
|
|
4
|
+
* the run carries none. Use it in a step that needs the target's URLs.
|
|
5
|
+
*
|
|
6
|
+
* @example snippet: scenarioHttpStep
|
|
7
|
+
*/
|
|
2
8
|
export declare const requireScenarioEnv: (scenarioStep: PikkuScenarioStepWire | undefined) => ScenarioEnvironment;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The environment the current scenario run targets, or a throw explaining that
|
|
3
|
+
* the run carries none. Use it in a step that needs the target's URLs.
|
|
4
|
+
*
|
|
5
|
+
* @example snippet: scenarioHttpStep
|
|
6
|
+
*/
|
|
1
7
|
export const requireScenarioEnv = (scenarioStep) => {
|
|
2
8
|
const env = scenarioStep?.env;
|
|
3
9
|
if (!env) {
|
|
@@ -9,6 +9,10 @@ export declare class WorkflowAsyncException extends Error {
|
|
|
9
9
|
readonly stepName: string;
|
|
10
10
|
constructor(runId: string, stepName: string);
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Thrown inside a workflow step when the run has been cancelled, so the step
|
|
14
|
+
* stops rather than finishing work nobody wants.
|
|
15
|
+
*/
|
|
12
16
|
export declare class WorkflowCancelledException extends Error {
|
|
13
17
|
readonly runId: string;
|
|
14
18
|
readonly reason?: string | undefined;
|
|
@@ -13,6 +13,10 @@ export class WorkflowAsyncException extends Error {
|
|
|
13
13
|
this.name = 'WorkflowAsyncException';
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Thrown inside a workflow step when the run has been cancelled, so the step
|
|
18
|
+
* stops rather than finishing work nobody wants.
|
|
19
|
+
*/
|
|
16
20
|
export class WorkflowCancelledException extends Error {
|
|
17
21
|
runId;
|
|
18
22
|
reason;
|
package/package.json
CHANGED
|
@@ -124,12 +124,12 @@ const barrelSpecifiers = (file: string) => {
|
|
|
124
124
|
* it otherwise never imports.
|
|
125
125
|
*/
|
|
126
126
|
const namesOwnedByALeaf = new Map<string, string>([
|
|
127
|
-
['defineCredential', '#pikku/
|
|
127
|
+
['defineCredential', '#pikku/auth'],
|
|
128
128
|
['defineSecret', '#pikku/secrets'],
|
|
129
129
|
['defineVariable', '#pikku/variables'],
|
|
130
130
|
['defineScope', '#pikku/scopes'],
|
|
131
131
|
['defineSystemRole', '#pikku/scopes'],
|
|
132
|
-
['cors', '#pikku/
|
|
132
|
+
['cors', '#pikku/middleware'],
|
|
133
133
|
['InvalidOriginError', '#pikku/error'],
|
|
134
134
|
])
|
|
135
135
|
|
|
@@ -13,19 +13,30 @@ export class PikkuError extends Error {
|
|
|
13
13
|
* survives serialization across a workflow step boundary and rehydration as a
|
|
14
14
|
* plain `Error`. Callers log the message alone for these, the full stack for
|
|
15
15
|
* everything else.
|
|
16
|
+
*
|
|
17
|
+
* @example snippet: isExpectedError
|
|
16
18
|
*/
|
|
17
19
|
export const isExpectedError = (error: unknown): boolean =>
|
|
18
20
|
error instanceof PikkuError ||
|
|
19
21
|
(error as { expected?: unknown } | null)?.expected === true
|
|
20
22
|
|
|
21
23
|
export interface ErrorDetails {
|
|
24
|
+
/** The HTTP status this error answers with, instead of a 500. */
|
|
22
25
|
status: number
|
|
26
|
+
/** What the caller is told. It leaves the process, so it must not name anything internal. */
|
|
23
27
|
message: string
|
|
28
|
+
/** The JSON-RPC code an MCP client is given, where the HTTP status has no equivalent. */
|
|
24
29
|
mcpCode?: number
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
export type PikkuErrorConstructor = new (...args: any[]) => Error
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Registers one of your own error classes with the HTTP status and message it
|
|
36
|
+
* should produce, so throwing it maps to a real response instead of a 500.
|
|
37
|
+
*
|
|
38
|
+
* @example snippet: addError
|
|
39
|
+
*/
|
|
29
40
|
export const addError = (
|
|
30
41
|
error: any,
|
|
31
42
|
{ status, message, mcpCode }: ErrorDetails
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export interface SerializedError {
|
|
2
|
+
/** What went wrong, carried across a boundary that cannot carry an Error. */
|
|
2
3
|
message: string
|
|
4
|
+
/** Present only where the failure was unexpected; a deliberate error is logged by its message alone. */
|
|
3
5
|
stack?: string
|
|
6
|
+
/** The error class's registered name, which is what a caller matches on rather than the message. */
|
|
4
7
|
code?: string
|
|
5
8
|
// Set for a deliberate PikkuError; survives step-boundary rehydration so
|
|
6
9
|
// the workflow runner logs the message alone rather than a stack trace.
|
|
@@ -29,7 +29,7 @@ import type { CorePikkuFunctionConfig } from './functions.types.js'
|
|
|
29
29
|
import { parseVersionedId } from '../version.js'
|
|
30
30
|
import type { SessionService } from '../services/user-session-service.js'
|
|
31
31
|
import { PikkuSessionService } from '../services/user-session-service.js'
|
|
32
|
-
import {
|
|
32
|
+
import { MissingSessionError, ReadonlySessionError } from '../errors/errors.js'
|
|
33
33
|
import { verifyScopes } from '../scopes.js'
|
|
34
34
|
import {
|
|
35
35
|
PikkuCredentialWireService,
|
|
@@ -83,7 +83,7 @@ async function resolveSession(
|
|
|
83
83
|
|
|
84
84
|
export const addFunction = (
|
|
85
85
|
funcName: string,
|
|
86
|
-
funcConfig: CorePikkuFunctionConfig<any, any>,
|
|
86
|
+
funcConfig: CorePikkuFunctionConfig<any, any, any, any, any>,
|
|
87
87
|
packageName: string | null = null
|
|
88
88
|
) => {
|
|
89
89
|
pikkuState(packageName, 'function', 'functions').set(funcName, funcConfig)
|
|
@@ -329,7 +329,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
329
329
|
resolveAddonAuth(packageName, addonInstance?.namespace)
|
|
330
330
|
) {
|
|
331
331
|
if (!session) {
|
|
332
|
-
throw new
|
|
332
|
+
throw new MissingSessionError('Authentication required')
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
335
|
} else {
|
|
@@ -339,7 +339,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
339
339
|
)
|
|
340
340
|
}
|
|
341
341
|
if (!session) {
|
|
342
|
-
throw new
|
|
342
|
+
throw new MissingSessionError('Authentication required')
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|