@amalgm/automations 0.2.0 → 0.2.2
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/AXIOMS.md +37 -16
- package/PURPOSE.md +14 -1
- package/README.md +5 -2
- package/dist/host/config.d.ts +1 -0
- package/dist/host/config.js +1 -0
- package/dist/host/main.js +16 -4
- package/dist/host/server.d.ts +3 -0
- package/dist/host/server.js +27 -8
- package/dist/src/automations.d.ts +4 -7
- package/dist/src/automations.js +13 -65
- package/dist/src/client.d.ts +1 -0
- package/dist/src/client.js +3 -2
- package/dist/src/contract.d.ts +4 -30
- package/dist/src/crud/automations.js +3 -3
- package/dist/src/crud/context.d.ts +1 -0
- package/dist/src/crud/context.js +10 -1
- package/dist/src/events-http.js +4 -0
- package/dist/src/executor.d.ts +12 -3
- package/dist/src/executor.js +163 -44
- package/dist/src/http.js +4 -0
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +4 -2
- package/dist/src/machine-client.d.ts +1 -0
- package/dist/src/machine-client.js +2 -0
- package/dist/src/machine.d.ts +2 -1
- package/dist/src/machine.js +6 -1
- package/dist/src/mcp.d.ts +3 -0
- package/dist/src/mcp.js +53 -50
- package/dist/src/plan.d.ts +3 -0
- package/dist/src/plan.js +48 -0
- package/dist/src/run-contract.d.ts +46 -0
- package/dist/src/run-contract.js +1 -0
- package/dist/src/run-journal.d.ts +8 -0
- package/dist/src/run-journal.js +56 -0
- package/dist/src/runner.d.ts +14 -0
- package/dist/src/runner.js +70 -0
- package/dist/src/schema.d.ts +46 -46
- package/dist/src/schema.js +18 -3
- package/dist/src/supabase-crud/mappers.js +2 -0
- package/dist/src/supabase-crud/rows.d.ts +2 -0
- package/dist/src/supabase-machine.js +2 -0
- package/dist/src/supabase-store.d.ts +1 -4
- package/dist/src/supabase-store.js +0 -24
- package/dist/src/tool-surface.d.ts +46 -0
- package/dist/src/tool-surface.js +125 -0
- package/dist/src/types.d.ts +1 -16
- package/package.json +5 -5
- package/skills/automations/SKILL.md +20 -15
- package/supabase/migrations/20260830010000_durable_step_retries.sql +332 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export function emptyJournal() {
|
|
2
|
+
return { version: 1, steps: [] };
|
|
3
|
+
}
|
|
4
|
+
export function runJournal(value, plan) {
|
|
5
|
+
if (value === undefined)
|
|
6
|
+
return emptyJournal();
|
|
7
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
8
|
+
throw new Error('Run step journal is invalid');
|
|
9
|
+
const source = value;
|
|
10
|
+
if (source.version !== 1 || !Array.isArray(source.steps))
|
|
11
|
+
throw new Error('Run step journal is invalid');
|
|
12
|
+
const planIds = new Set(plan.map(({ id }) => id));
|
|
13
|
+
const steps = source.steps.map(runStep);
|
|
14
|
+
const ids = new Set();
|
|
15
|
+
for (const step of steps) {
|
|
16
|
+
if (!planIds.has(step.id))
|
|
17
|
+
throw new Error(`Run step is not in the immutable plan: ${step.id}`);
|
|
18
|
+
if (ids.has(step.id))
|
|
19
|
+
throw new Error(`Run step journal has a duplicate id: ${step.id}`);
|
|
20
|
+
ids.add(step.id);
|
|
21
|
+
}
|
|
22
|
+
return { version: 1, steps };
|
|
23
|
+
}
|
|
24
|
+
export function completed(journal, stepId) {
|
|
25
|
+
return journal.steps.some((step) => step.id === stepId && step.status === 'completed');
|
|
26
|
+
}
|
|
27
|
+
export function stepAttempt(journal, stepId) {
|
|
28
|
+
return journal.steps.find((step) => step.id === stepId)?.attempts ?? 0;
|
|
29
|
+
}
|
|
30
|
+
export function putStep(journal, step) {
|
|
31
|
+
const index = journal.steps.findIndex(({ id }) => id === step.id);
|
|
32
|
+
const steps = [...journal.steps];
|
|
33
|
+
if (index === -1)
|
|
34
|
+
steps.push(step);
|
|
35
|
+
else
|
|
36
|
+
steps[index] = step;
|
|
37
|
+
return { version: 1, steps };
|
|
38
|
+
}
|
|
39
|
+
/** Journals are constructed from JSON fields only; this is the persistence boundary. */
|
|
40
|
+
export function journalJson(journal) {
|
|
41
|
+
return journal;
|
|
42
|
+
}
|
|
43
|
+
function runStep(value) {
|
|
44
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
45
|
+
throw new Error('Run step is invalid');
|
|
46
|
+
const item = value;
|
|
47
|
+
if (typeof item.id !== 'string' || !item.id)
|
|
48
|
+
throw new Error('Run step id is invalid');
|
|
49
|
+
if (item.status !== 'running' && item.status !== 'completed' && item.status !== 'failed') {
|
|
50
|
+
throw new Error(`Run step status is invalid: ${item.id}`);
|
|
51
|
+
}
|
|
52
|
+
if (!Number.isInteger(item.attempts) || Number(item.attempts) < 1 || typeof item.startedAt !== 'string') {
|
|
53
|
+
throw new Error(`Run step attempt is invalid: ${item.id}`);
|
|
54
|
+
}
|
|
55
|
+
return item;
|
|
56
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ClaimedAutomationRun, MachineRuns } from './machine.js';
|
|
2
|
+
export interface AutomationMachineRunnerOptions {
|
|
3
|
+
readonly runs: MachineRuns;
|
|
4
|
+
readonly execute: (run: ClaimedAutomationRun) => Promise<void>;
|
|
5
|
+
readonly batchSize?: number;
|
|
6
|
+
readonly leaseSeconds?: number;
|
|
7
|
+
readonly pollIntervalMs?: number;
|
|
8
|
+
readonly maxBackoffMs?: number;
|
|
9
|
+
readonly log?: (event: string, details?: Readonly<Record<string, unknown>>) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createAutomationMachineRunner(options: AutomationMachineRunnerOptions): Readonly<{
|
|
12
|
+
start(): void;
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export function createAutomationMachineRunner(options) {
|
|
2
|
+
const batchSize = integer(options.batchSize ?? 8, 1, 20, 'batchSize');
|
|
3
|
+
const leaseSeconds = integer(options.leaseSeconds ?? 60, 30, 900, 'leaseSeconds');
|
|
4
|
+
const pollIntervalMs = integer(options.pollIntervalMs ?? 1_000, 1, 60_000, 'pollIntervalMs');
|
|
5
|
+
const maxBackoffMs = integer(options.maxBackoffMs ?? Math.max(30_000, pollIntervalMs), pollIntervalMs, 300_000, 'maxBackoffMs');
|
|
6
|
+
let active = null;
|
|
7
|
+
let timer = null;
|
|
8
|
+
let stopped = true;
|
|
9
|
+
let failures = 0;
|
|
10
|
+
let nextDelay = pollIntervalMs;
|
|
11
|
+
const schedule = (delay) => {
|
|
12
|
+
if (stopped)
|
|
13
|
+
return;
|
|
14
|
+
timer = setTimeout(drain, delay);
|
|
15
|
+
timer.unref?.();
|
|
16
|
+
};
|
|
17
|
+
const drain = () => {
|
|
18
|
+
if (stopped || active)
|
|
19
|
+
return active;
|
|
20
|
+
active = options.runs.claim({ limit: batchSize, leaseSeconds })
|
|
21
|
+
.then(async (runs) => {
|
|
22
|
+
failures = 0;
|
|
23
|
+
if (runs.length)
|
|
24
|
+
options.log?.('automations.claimed', { count: runs.length });
|
|
25
|
+
const settled = await Promise.allSettled(runs.map(options.execute));
|
|
26
|
+
settled.forEach((result) => {
|
|
27
|
+
if (result.status === 'rejected') {
|
|
28
|
+
options.log?.('automations.run.failed', { error: safe(result.reason) });
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
nextDelay = runs.length === batchSize ? 0 : pollIntervalMs;
|
|
32
|
+
})
|
|
33
|
+
.catch((error) => {
|
|
34
|
+
failures += 1;
|
|
35
|
+
const delayMs = Math.min(maxBackoffMs, pollIntervalMs * (2 ** Math.min(failures - 1, 10)));
|
|
36
|
+
options.log?.('automations.poll.failed', { error: safe(error), retryInMs: delayMs });
|
|
37
|
+
nextDelay = delayMs;
|
|
38
|
+
})
|
|
39
|
+
.finally(() => {
|
|
40
|
+
active = null;
|
|
41
|
+
schedule(nextDelay);
|
|
42
|
+
});
|
|
43
|
+
return active;
|
|
44
|
+
};
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
start() {
|
|
47
|
+
if (!stopped)
|
|
48
|
+
return;
|
|
49
|
+
stopped = false;
|
|
50
|
+
failures = 0;
|
|
51
|
+
void drain();
|
|
52
|
+
},
|
|
53
|
+
async close() {
|
|
54
|
+
stopped = true;
|
|
55
|
+
if (timer)
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
timer = null;
|
|
58
|
+
await active;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function integer(value, minimum, maximum, name) {
|
|
63
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
64
|
+
throw new Error(`${name} must be an integer from ${minimum} to ${maximum}`);
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
function safe(error) {
|
|
69
|
+
return (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, ' ').slice(0, 500);
|
|
70
|
+
}
|
package/dist/src/schema.d.ts
CHANGED
|
@@ -13,22 +13,22 @@ export declare const pageQuerySchema: z.ZodObject<{
|
|
|
13
13
|
}>;
|
|
14
14
|
export declare const createAutomationSchema: z.ZodObject<{
|
|
15
15
|
id: z.ZodOptional<z.ZodString>;
|
|
16
|
-
targetId: z.ZodString
|
|
16
|
+
targetId: z.ZodOptional<z.ZodString>;
|
|
17
17
|
name: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
18
18
|
description: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
19
19
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
20
20
|
}, "strict", z.ZodTypeAny, {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
targetId?: string | undefined;
|
|
22
|
+
enabled?: boolean | undefined;
|
|
23
23
|
name?: string | undefined;
|
|
24
|
+
id?: string | undefined;
|
|
24
25
|
description?: string | undefined;
|
|
25
|
-
enabled?: boolean | undefined;
|
|
26
26
|
}, {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
targetId?: string | undefined;
|
|
28
|
+
enabled?: boolean | undefined;
|
|
29
29
|
name?: string | undefined;
|
|
30
|
+
id?: string | undefined;
|
|
30
31
|
description?: string | undefined;
|
|
31
|
-
enabled?: boolean | undefined;
|
|
32
32
|
}>;
|
|
33
33
|
export declare const updateAutomationSchema: z.ZodEffects<z.ZodObject<{
|
|
34
34
|
targetId: z.ZodOptional<z.ZodString>;
|
|
@@ -37,24 +37,24 @@ export declare const updateAutomationSchema: z.ZodEffects<z.ZodObject<{
|
|
|
37
37
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
38
38
|
}, "strict", z.ZodTypeAny, {
|
|
39
39
|
targetId?: string | undefined;
|
|
40
|
+
enabled?: boolean | undefined;
|
|
40
41
|
name?: string | null | undefined;
|
|
41
42
|
description?: string | null | undefined;
|
|
42
|
-
enabled?: boolean | undefined;
|
|
43
43
|
}, {
|
|
44
44
|
targetId?: string | undefined;
|
|
45
|
+
enabled?: boolean | undefined;
|
|
45
46
|
name?: string | null | undefined;
|
|
46
47
|
description?: string | null | undefined;
|
|
47
|
-
enabled?: boolean | undefined;
|
|
48
48
|
}>, {
|
|
49
49
|
targetId?: string | undefined;
|
|
50
|
+
enabled?: boolean | undefined;
|
|
50
51
|
name?: string | null | undefined;
|
|
51
52
|
description?: string | null | undefined;
|
|
52
|
-
enabled?: boolean | undefined;
|
|
53
53
|
}, {
|
|
54
54
|
targetId?: string | undefined;
|
|
55
|
+
enabled?: boolean | undefined;
|
|
55
56
|
name?: string | null | undefined;
|
|
56
57
|
description?: string | null | undefined;
|
|
57
|
-
enabled?: boolean | undefined;
|
|
58
58
|
}>;
|
|
59
59
|
export declare const listAutomationsSchema: z.ZodObject<{
|
|
60
60
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
@@ -63,15 +63,15 @@ export declare const listAutomationsSchema: z.ZodObject<{
|
|
|
63
63
|
targetId: z.ZodOptional<z.ZodString>;
|
|
64
64
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
65
65
|
}, "strict", z.ZodTypeAny, {
|
|
66
|
-
limit?: number | undefined;
|
|
67
|
-
offset?: number | undefined;
|
|
68
66
|
targetId?: string | undefined;
|
|
69
67
|
enabled?: boolean | undefined;
|
|
70
|
-
}, {
|
|
71
68
|
limit?: number | undefined;
|
|
72
69
|
offset?: number | undefined;
|
|
70
|
+
}, {
|
|
73
71
|
targetId?: string | undefined;
|
|
74
72
|
enabled?: boolean | undefined;
|
|
73
|
+
limit?: number | undefined;
|
|
74
|
+
offset?: number | undefined;
|
|
75
75
|
}>;
|
|
76
76
|
export declare const createScheduleTriggerSchema: z.ZodObject<{
|
|
77
77
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -80,16 +80,16 @@ export declare const createScheduleTriggerSchema: z.ZodObject<{
|
|
|
80
80
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
81
81
|
maxOccurrences: z.ZodOptional<z.ZodNumber>;
|
|
82
82
|
}, "strict", z.ZodTypeAny, {
|
|
83
|
-
id?: string | undefined;
|
|
84
83
|
cron: string;
|
|
85
|
-
timezone?: string | undefined;
|
|
86
84
|
enabled?: boolean | undefined;
|
|
85
|
+
id?: string | undefined;
|
|
86
|
+
timezone?: string | undefined;
|
|
87
87
|
maxOccurrences?: number | undefined;
|
|
88
88
|
}, {
|
|
89
|
-
id?: string | undefined;
|
|
90
89
|
cron: string;
|
|
91
|
-
timezone?: string | undefined;
|
|
92
90
|
enabled?: boolean | undefined;
|
|
91
|
+
id?: string | undefined;
|
|
92
|
+
timezone?: string | undefined;
|
|
93
93
|
maxOccurrences?: number | undefined;
|
|
94
94
|
}>;
|
|
95
95
|
export declare const updateScheduleTriggerSchema: z.ZodEffects<z.ZodObject<{
|
|
@@ -98,24 +98,24 @@ export declare const updateScheduleTriggerSchema: z.ZodEffects<z.ZodObject<{
|
|
|
98
98
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
99
99
|
maxOccurrences: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
100
100
|
}, "strict", z.ZodTypeAny, {
|
|
101
|
+
enabled?: boolean | undefined;
|
|
101
102
|
cron?: string | undefined;
|
|
102
103
|
timezone?: string | undefined;
|
|
103
|
-
enabled?: boolean | undefined;
|
|
104
104
|
maxOccurrences?: number | null | undefined;
|
|
105
105
|
}, {
|
|
106
|
+
enabled?: boolean | undefined;
|
|
106
107
|
cron?: string | undefined;
|
|
107
108
|
timezone?: string | undefined;
|
|
108
|
-
enabled?: boolean | undefined;
|
|
109
109
|
maxOccurrences?: number | null | undefined;
|
|
110
110
|
}>, {
|
|
111
|
+
enabled?: boolean | undefined;
|
|
111
112
|
cron?: string | undefined;
|
|
112
113
|
timezone?: string | undefined;
|
|
113
|
-
enabled?: boolean | undefined;
|
|
114
114
|
maxOccurrences?: number | null | undefined;
|
|
115
115
|
}, {
|
|
116
|
+
enabled?: boolean | undefined;
|
|
116
117
|
cron?: string | undefined;
|
|
117
118
|
timezone?: string | undefined;
|
|
118
|
-
enabled?: boolean | undefined;
|
|
119
119
|
maxOccurrences?: number | null | undefined;
|
|
120
120
|
}>;
|
|
121
121
|
export declare const createWebhookTriggerSchema: z.ZodObject<{
|
|
@@ -125,17 +125,17 @@ export declare const createWebhookTriggerSchema: z.ZodObject<{
|
|
|
125
125
|
secret: z.ZodString;
|
|
126
126
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
127
127
|
}, "strict", z.ZodTypeAny, {
|
|
128
|
-
id?: string | undefined;
|
|
129
|
-
source?: string | undefined;
|
|
130
|
-
event?: string | undefined;
|
|
131
128
|
secret: string;
|
|
132
129
|
enabled?: boolean | undefined;
|
|
133
|
-
}, {
|
|
134
|
-
id?: string | undefined;
|
|
135
|
-
source?: string | undefined;
|
|
136
130
|
event?: string | undefined;
|
|
131
|
+
source?: string | undefined;
|
|
132
|
+
id?: string | undefined;
|
|
133
|
+
}, {
|
|
137
134
|
secret: string;
|
|
138
135
|
enabled?: boolean | undefined;
|
|
136
|
+
event?: string | undefined;
|
|
137
|
+
source?: string | undefined;
|
|
138
|
+
id?: string | undefined;
|
|
139
139
|
}>;
|
|
140
140
|
export declare const updateWebhookTriggerSchema: z.ZodEffects<z.ZodObject<{
|
|
141
141
|
source: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
@@ -143,25 +143,25 @@ export declare const updateWebhookTriggerSchema: z.ZodEffects<z.ZodObject<{
|
|
|
143
143
|
secret: z.ZodOptional<z.ZodString>;
|
|
144
144
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
145
145
|
}, "strict", z.ZodTypeAny, {
|
|
146
|
-
|
|
146
|
+
enabled?: boolean | undefined;
|
|
147
147
|
event?: string | undefined;
|
|
148
148
|
secret?: string | undefined;
|
|
149
|
-
enabled?: boolean | undefined;
|
|
150
|
-
}, {
|
|
151
149
|
source?: string | undefined;
|
|
150
|
+
}, {
|
|
151
|
+
enabled?: boolean | undefined;
|
|
152
152
|
event?: string | undefined;
|
|
153
153
|
secret?: string | undefined;
|
|
154
|
-
enabled?: boolean | undefined;
|
|
155
|
-
}>, {
|
|
156
154
|
source?: string | undefined;
|
|
155
|
+
}>, {
|
|
156
|
+
enabled?: boolean | undefined;
|
|
157
157
|
event?: string | undefined;
|
|
158
158
|
secret?: string | undefined;
|
|
159
|
-
enabled?: boolean | undefined;
|
|
160
|
-
}, {
|
|
161
159
|
source?: string | undefined;
|
|
160
|
+
}, {
|
|
161
|
+
enabled?: boolean | undefined;
|
|
162
162
|
event?: string | undefined;
|
|
163
163
|
secret?: string | undefined;
|
|
164
|
-
|
|
164
|
+
source?: string | undefined;
|
|
165
165
|
}>;
|
|
166
166
|
export declare const createWorkflowSchema: z.ZodObject<{
|
|
167
167
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -171,17 +171,17 @@ export declare const createWorkflowSchema: z.ZodObject<{
|
|
|
171
171
|
allowlist: z.ZodOptional<z.ZodType<Json, z.ZodTypeDef, Json>>;
|
|
172
172
|
limits: z.ZodOptional<z.ZodType<Json, z.ZodTypeDef, Json>>;
|
|
173
173
|
}, "strict", z.ZodTypeAny, {
|
|
174
|
-
id?: string | undefined;
|
|
175
|
-
name?: string | undefined;
|
|
176
174
|
script: string;
|
|
175
|
+
name?: string | undefined;
|
|
177
176
|
compiled?: Json | undefined;
|
|
177
|
+
id?: string | undefined;
|
|
178
178
|
allowlist?: Json | undefined;
|
|
179
179
|
limits?: Json | undefined;
|
|
180
180
|
}, {
|
|
181
|
-
id?: string | undefined;
|
|
182
|
-
name?: string | undefined;
|
|
183
181
|
script: string;
|
|
182
|
+
name?: string | undefined;
|
|
184
183
|
compiled?: Json | undefined;
|
|
184
|
+
id?: string | undefined;
|
|
185
185
|
allowlist?: Json | undefined;
|
|
186
186
|
limits?: Json | undefined;
|
|
187
187
|
}>;
|
|
@@ -193,26 +193,26 @@ export declare const updateWorkflowSchema: z.ZodEffects<z.ZodObject<{
|
|
|
193
193
|
limits: z.ZodOptional<z.ZodNullable<z.ZodType<Json, z.ZodTypeDef, Json>>>;
|
|
194
194
|
}, "strict", z.ZodTypeAny, {
|
|
195
195
|
name?: string | null | undefined;
|
|
196
|
-
script?: string | undefined;
|
|
197
196
|
compiled?: Json | undefined;
|
|
197
|
+
script?: string | undefined;
|
|
198
198
|
allowlist?: Json | undefined;
|
|
199
199
|
limits?: Json | undefined;
|
|
200
200
|
}, {
|
|
201
201
|
name?: string | null | undefined;
|
|
202
|
-
script?: string | undefined;
|
|
203
202
|
compiled?: Json | undefined;
|
|
203
|
+
script?: string | undefined;
|
|
204
204
|
allowlist?: Json | undefined;
|
|
205
205
|
limits?: Json | undefined;
|
|
206
206
|
}>, {
|
|
207
207
|
name?: string | null | undefined;
|
|
208
|
-
script?: string | undefined;
|
|
209
208
|
compiled?: Json | undefined;
|
|
209
|
+
script?: string | undefined;
|
|
210
210
|
allowlist?: Json | undefined;
|
|
211
211
|
limits?: Json | undefined;
|
|
212
212
|
}, {
|
|
213
213
|
name?: string | null | undefined;
|
|
214
|
-
script?: string | undefined;
|
|
215
214
|
compiled?: Json | undefined;
|
|
215
|
+
script?: string | undefined;
|
|
216
216
|
allowlist?: Json | undefined;
|
|
217
217
|
limits?: Json | undefined;
|
|
218
218
|
}>;
|
|
@@ -222,13 +222,13 @@ export declare const listRunsSchema: z.ZodObject<{
|
|
|
222
222
|
} & {
|
|
223
223
|
status: z.ZodOptional<z.ZodEnum<["pending", "sent", "running", "completed", "failed"]>>;
|
|
224
224
|
}, "strict", z.ZodTypeAny, {
|
|
225
|
+
status?: "pending" | "sent" | "running" | "completed" | "failed" | undefined;
|
|
225
226
|
limit?: number | undefined;
|
|
226
227
|
offset?: number | undefined;
|
|
227
|
-
status?: "completed" | "failed" | "pending" | "running" | "sent" | undefined;
|
|
228
228
|
}, {
|
|
229
|
+
status?: "pending" | "sent" | "running" | "completed" | "failed" | undefined;
|
|
229
230
|
limit?: number | undefined;
|
|
230
231
|
offset?: number | undefined;
|
|
231
|
-
status?: "completed" | "failed" | "pending" | "running" | "sent" | undefined;
|
|
232
232
|
}>;
|
|
233
233
|
export declare function parseCreateAutomation(value: unknown): CreateAutomation;
|
|
234
234
|
export declare function parseUpdateAutomation(value: unknown): UpdateAutomation;
|
package/dist/src/schema.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod/v3';
|
|
2
2
|
import { ValidationError } from './errors.js';
|
|
3
|
+
import { compiledAutomationPlan } from './plan.js';
|
|
3
4
|
import { IDENTIFIER } from './validation.js';
|
|
4
5
|
const maxPageSize = 100;
|
|
5
6
|
const identifierMessage = 'Identifier is invalid';
|
|
@@ -21,7 +22,7 @@ const jsonSchema = z.lazy(() => z.union([
|
|
|
21
22
|
]));
|
|
22
23
|
export const createAutomationSchema = z.object({
|
|
23
24
|
id: identifierSchema.optional(),
|
|
24
|
-
targetId: identifierSchema,
|
|
25
|
+
targetId: identifierSchema.optional(),
|
|
25
26
|
name: text(500, 'Automation name').optional(),
|
|
26
27
|
description: text(10_000, 'Automation description').optional(),
|
|
27
28
|
enabled: z.boolean().optional(),
|
|
@@ -102,10 +103,16 @@ export function parseUpdateWebhookTrigger(value) {
|
|
|
102
103
|
return parse(updateWebhookTriggerSchema, value);
|
|
103
104
|
}
|
|
104
105
|
export function parseCreateWorkflow(value) {
|
|
105
|
-
|
|
106
|
+
const workflow = parse(createWorkflowSchema, value);
|
|
107
|
+
if (workflow.compiled !== undefined)
|
|
108
|
+
validateCompiledPlan(workflow.compiled);
|
|
109
|
+
return workflow;
|
|
106
110
|
}
|
|
107
111
|
export function parseUpdateWorkflow(value) {
|
|
108
|
-
|
|
112
|
+
const workflow = parse(updateWorkflowSchema, value);
|
|
113
|
+
if (workflow.compiled !== undefined && workflow.compiled !== null)
|
|
114
|
+
validateCompiledPlan(workflow.compiled);
|
|
115
|
+
return workflow;
|
|
109
116
|
}
|
|
110
117
|
export function parsePageQuery(value) {
|
|
111
118
|
return parse(pageQuerySchema, value);
|
|
@@ -119,3 +126,11 @@ export function parse(schema, value) {
|
|
|
119
126
|
return result.data;
|
|
120
127
|
throw new ValidationError(result.error.issues[0]?.message || 'Input is invalid');
|
|
121
128
|
}
|
|
129
|
+
function validateCompiledPlan(value) {
|
|
130
|
+
try {
|
|
131
|
+
compiledAutomationPlan(value);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw new ValidationError(error instanceof Error ? error.message : String(error));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -58,6 +58,8 @@ export function run(row) {
|
|
|
58
58
|
workflowId: row.workflow_id,
|
|
59
59
|
targetId: row.target_id,
|
|
60
60
|
status: row.status,
|
|
61
|
+
attempts: row.attempts,
|
|
62
|
+
...(row.retry_at ? { retryAt: timestamp(row.retry_at) } : {}),
|
|
61
63
|
input: row.input,
|
|
62
64
|
createdAt: timestamp(row.created_at),
|
|
63
65
|
...(row.sent_at ? { sentAt: timestamp(row.sent_at) } : {}),
|
|
@@ -43,6 +43,7 @@ function run(row) {
|
|
|
43
43
|
input: row.input,
|
|
44
44
|
status: row.status,
|
|
45
45
|
attempts: row.attempts,
|
|
46
|
+
...(row.retry_at ? { retryAt: timestamp(row.retry_at) } : {}),
|
|
46
47
|
leaseToken: row.lease_token,
|
|
47
48
|
leaseExpiresAt: timestamp(row.lease_expires_at),
|
|
48
49
|
createdAt: timestamp(row.created_at),
|
|
@@ -56,6 +57,7 @@ function run(row) {
|
|
|
56
57
|
function update(value) {
|
|
57
58
|
return {
|
|
58
59
|
status: value.status,
|
|
60
|
+
...(value.retryAt === undefined ? {} : { retryAt: value.retryAt }),
|
|
59
61
|
...(value.output === undefined ? {} : { output: value.output }),
|
|
60
62
|
...(value.error === undefined ? {} : { error: value.error }),
|
|
61
63
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AutomationStore, AutomationTarget, AutomationRun, DueCronTrigger, RunInput,
|
|
1
|
+
import type { AutomationStore, AutomationTarget, AutomationRun, DueCronTrigger, RunInput, StoredEventTrigger } from './types.js';
|
|
2
2
|
export interface SupabaseRpcClient {
|
|
3
3
|
rpc(functionName: string, arguments_: Record<string, unknown>): PromiseLike<{
|
|
4
4
|
data: unknown;
|
|
@@ -17,7 +17,4 @@ export declare class SupabaseStore implements AutomationStore {
|
|
|
17
17
|
kind: 'event';
|
|
18
18
|
}>, now: Date): Promise<AutomationRun | null>;
|
|
19
19
|
enqueueCron(trigger: DueCronTrigger, nextRunAt: string, now: Date): Promise<AutomationRun | null>;
|
|
20
|
-
pendingRuns(target: AutomationTarget): Promise<AutomationRun[]>;
|
|
21
|
-
markSent(runId: string, target: AutomationTarget, now: Date): Promise<boolean>;
|
|
22
|
-
updateRun(target: AutomationTarget, runId: string, update: RunUpdate): Promise<AutomationRun | null>;
|
|
23
20
|
}
|
|
@@ -61,30 +61,6 @@ export class SupabaseStore {
|
|
|
61
61
|
scheduledFor: trigger.nextRunAt,
|
|
62
62
|
}, now, nextRunAt);
|
|
63
63
|
}
|
|
64
|
-
async pendingRuns(target) {
|
|
65
|
-
const rows = await this.#call('list_amalgm_pending_runs', {
|
|
66
|
-
p_user_id: target.userId,
|
|
67
|
-
p_target_id: target.targetId,
|
|
68
|
-
});
|
|
69
|
-
return rows.map(automationRun);
|
|
70
|
-
}
|
|
71
|
-
markSent(runId, target, now) {
|
|
72
|
-
return this.#call('mark_amalgm_run_sent', {
|
|
73
|
-
p_run_id: runId,
|
|
74
|
-
p_user_id: target.userId,
|
|
75
|
-
p_target_id: target.targetId,
|
|
76
|
-
p_now: now.toISOString(),
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
async updateRun(target, runId, update) {
|
|
80
|
-
const rows = await this.#call('update_amalgm_run', {
|
|
81
|
-
p_run_id: runId,
|
|
82
|
-
p_user_id: target.userId,
|
|
83
|
-
p_target_id: target.targetId,
|
|
84
|
-
p_update: update,
|
|
85
|
-
});
|
|
86
|
-
return rows[0] ? automationRun(rows[0]) : null;
|
|
87
|
-
}
|
|
88
64
|
async #enqueue(trigger, input, now, nextRunAt) {
|
|
89
65
|
const rows = await this.#call('enqueue_amalgm_run', {
|
|
90
66
|
p_kind: trigger.kind,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Automation, AutomationCrud, AutomationRun, CreateAutomation, CreateScheduleTrigger, CreateWebhookTrigger, CreateWorkflow, ListAutomations, ListRuns, Page, Trigger, UpdateAutomation, UpdateScheduleTrigger, UpdateWebhookTrigger, UpdateWorkflow, Workflow } from './contract.js';
|
|
2
|
+
export interface AutomationView {
|
|
3
|
+
automation: Automation;
|
|
4
|
+
triggers: Trigger[];
|
|
5
|
+
workflow: Workflow | null;
|
|
6
|
+
runs?: Page<AutomationRun>;
|
|
7
|
+
}
|
|
8
|
+
export interface CreateAutomationDefinition extends CreateAutomation {
|
|
9
|
+
schedules?: CreateScheduleTrigger[];
|
|
10
|
+
webhooks?: CreateWebhookTrigger[];
|
|
11
|
+
workflow?: CreateWorkflow;
|
|
12
|
+
}
|
|
13
|
+
interface Changes<Create extends {
|
|
14
|
+
id?: string;
|
|
15
|
+
}, Update> {
|
|
16
|
+
create?: Create[];
|
|
17
|
+
update?: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
patch: Update;
|
|
20
|
+
}>;
|
|
21
|
+
delete?: string[];
|
|
22
|
+
}
|
|
23
|
+
export type WorkflowChange = {
|
|
24
|
+
create: CreateWorkflow;
|
|
25
|
+
} | {
|
|
26
|
+
update: UpdateWorkflow;
|
|
27
|
+
} | {
|
|
28
|
+
delete: true;
|
|
29
|
+
};
|
|
30
|
+
export interface UpdateAutomationDefinition {
|
|
31
|
+
patch?: UpdateAutomation;
|
|
32
|
+
schedules?: Changes<CreateScheduleTrigger, UpdateScheduleTrigger>;
|
|
33
|
+
webhooks?: Changes<CreateWebhookTrigger, UpdateWebhookTrigger>;
|
|
34
|
+
workflow?: WorkflowChange;
|
|
35
|
+
}
|
|
36
|
+
export interface AutomationToolSurface {
|
|
37
|
+
create(input: CreateAutomationDefinition): Promise<AutomationView>;
|
|
38
|
+
list(query?: ListAutomations): Promise<Page<Automation>>;
|
|
39
|
+
get(automationId: string, runs?: false | ListRuns): Promise<AutomationView>;
|
|
40
|
+
update(automationId: string, input: UpdateAutomationDefinition): Promise<AutomationView>;
|
|
41
|
+
delete(automationId: string): Promise<{
|
|
42
|
+
deleted: string;
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
45
|
+
export declare function createAutomationToolSurface(sdk: AutomationCrud): AutomationToolSurface;
|
|
46
|
+
export {};
|