@uniformdev/automations-sdk 20.50.2-alpha.167 → 20.72.3-alpha.23

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/dist/ai/index.mjs CHANGED
@@ -51,9 +51,6 @@ var ScoutClient = class extends ApiClient {
51
51
  body: JSON.stringify({ messages, outputSchema })
52
52
  }
53
53
  );
54
- if (result.outcome === "over-credit-limit") {
55
- throw new Error("Scout is out of AI credits for this team.");
56
- }
57
54
  if (params.outputSchema && result.structuredOutput == null) {
58
55
  throw new Error("Scout finished without recording structured output.");
59
56
  }
@@ -415,38 +415,45 @@ interface paths {
415
415
  name: string;
416
416
  /** @description Optional description. */
417
417
  description: string | null;
418
- /** @description How the automation is triggered. */
419
- trigger: {
418
+ /** @description The triggers this automation subscribes to. */
419
+ triggers: {
420
+ /** @description How the automation is triggered. */
421
+ config: {
422
+ /**
423
+ * @description The internal webhook event name that triggers this automation.
424
+ * @enum {string}
425
+ */
426
+ type: "asset.deleted" | "asset.published" | "composition.changed" | "composition.deleted" | "composition.published" | "composition.release.changed" | "composition.release.deleted" | "composition.release.published" | "composition.release.restored" | "entry.changed" | "entry.deleted" | "entry.published" | "entry.release.changed" | "entry.release.deleted" | "entry.release.published" | "entry.release.restored" | "manifest.published" | "projectmap.delete" | "projectmap.node.delete" | "projectmap.node.insert" | "projectmap.node.update" | "projectmap.update" | "redirect.delete" | "redirect.insert" | "redirect.update" | "release.changed" | "release.deleted" | "release.launch_started" | "release.launched" | "workflow.transition";
427
+ /** @description Optional CEL boolean expression evaluated against { input, trigger }; the automation runs only when it is true. */
428
+ filter?: string;
429
+ } | {
430
+ /** @enum {string} */
431
+ type: "schedule";
432
+ /** @description RFC 5545 recurrence rule for when the automation runs. */
433
+ rrule: string;
434
+ /** @description IANA timezone used to evaluate the recurrence rule. */
435
+ timezone: string;
436
+ } | {
437
+ /** @enum {string} */
438
+ type: "incomingWebhook";
439
+ /** @description Optional CEL boolean expression evaluated against { input, trigger }; the automation runs only when it is true. */
440
+ filter?: string;
441
+ } | {
442
+ /** @enum {string} */
443
+ type: "aiTool";
444
+ /** @description JSON Schema describing the AI tool arguments. */
445
+ inputSchema: {
446
+ [key: string]: unknown;
447
+ };
448
+ };
420
449
  /**
421
- * @description The internal webhook event name that triggers this automation.
422
- * @enum {string}
450
+ * Format: date-time
451
+ * @description Next upcoming run for this trigger; null for non-schedule triggers.
423
452
  */
424
- type: "asset.deleted" | "asset.published" | "composition.changed" | "composition.deleted" | "composition.published" | "composition.release.changed" | "composition.release.deleted" | "composition.release.published" | "composition.release.restored" | "entry.changed" | "entry.deleted" | "entry.published" | "entry.release.changed" | "entry.release.deleted" | "entry.release.published" | "entry.release.restored" | "manifest.published" | "projectmap.delete" | "projectmap.node.delete" | "projectmap.node.insert" | "projectmap.node.update" | "projectmap.update" | "redirect.delete" | "redirect.insert" | "redirect.update" | "release.changed" | "release.deleted" | "release.launch_started" | "release.launched" | "workflow.transition";
425
- } | {
426
- /** @enum {string} */
427
- type: "schedule";
428
- /** @description RFC 5545 recurrence rule for when the automation runs. */
429
- rrule: string;
430
- /** @description IANA timezone used to evaluate the recurrence rule. */
431
- timezone: string;
432
- } | {
433
- /** @enum {string} */
434
- type: "incomingWebhook";
435
- } | {
436
- /** @enum {string} */
437
- type: "aiTool";
438
- /** @description JSON Schema describing the AI tool arguments. */
439
- inputSchema: {
440
- [key: string]: unknown;
441
- };
442
- };
453
+ nextRunAt: string | null;
454
+ }[];
443
455
  /** @description Whether the automation is enabled. */
444
456
  enabled: boolean;
445
- /**
446
- * Format: date-time
447
- * @description Next scheduled run time, or null when not applicable.
448
- */
449
- nextRunAt: string | null;
450
457
  /**
451
458
  * Format: date-time
452
459
  * @description When the automation code was last deployed.
@@ -503,13 +510,15 @@ interface paths {
503
510
  name: string;
504
511
  /** @description For automations triggered as an AI tool, this is used to determine when an LLM should call the automation. For other triggers, this is for your reference and optional. */
505
512
  description?: string;
506
- /** @description How the automation is triggered. */
507
- trigger: {
513
+ /** @description The triggers this automation subscribes to. */
514
+ triggers: ({
508
515
  /**
509
516
  * @description The internal webhook event name that triggers this automation.
510
517
  * @enum {string}
511
518
  */
512
519
  type: "asset.deleted" | "asset.published" | "composition.changed" | "composition.deleted" | "composition.published" | "composition.release.changed" | "composition.release.deleted" | "composition.release.published" | "composition.release.restored" | "entry.changed" | "entry.deleted" | "entry.published" | "entry.release.changed" | "entry.release.deleted" | "entry.release.published" | "entry.release.restored" | "manifest.published" | "projectmap.delete" | "projectmap.node.delete" | "projectmap.node.insert" | "projectmap.node.update" | "projectmap.update" | "redirect.delete" | "redirect.insert" | "redirect.update" | "release.changed" | "release.deleted" | "release.launch_started" | "release.launched" | "workflow.transition";
520
+ /** @description Optional CEL boolean expression evaluated against { input, trigger }; the automation runs only when it is true. */
521
+ filter?: string;
513
522
  } | {
514
523
  /** @enum {string} */
515
524
  type: "schedule";
@@ -520,6 +529,8 @@ interface paths {
520
529
  } | {
521
530
  /** @enum {string} */
522
531
  type: "incomingWebhook";
532
+ /** @description Optional CEL boolean expression evaluated against { input, trigger }; the automation runs only when it is true. */
533
+ filter?: string;
523
534
  } | {
524
535
  /** @enum {string} */
525
536
  type: "aiTool";
@@ -527,7 +538,7 @@ interface paths {
527
538
  inputSchema: {
528
539
  [key: string]: unknown;
529
540
  };
530
- };
541
+ })[];
531
542
  /** @description Role grants for the automation identity. The caller must hold each requested role (or be a team admin). When omitted, the automation will not receive Uniform API access credentials. */
532
543
  permissions?: {
533
544
  /** @description Role grant(s) on the project the automation is deployed to. */
@@ -733,7 +744,8 @@ interface components {
733
744
 
734
745
  type AutomationsListResponse = paths['/api/v1/automations']['get']['responses']['200']['content']['application/json'];
735
746
  type AutomationSummary = AutomationsListResponse['automations'][number];
736
- type AutomationTriggerType = AutomationSummary['trigger']['type'];
747
+ type AutomationTrigger = AutomationSummary['triggers'][number];
748
+ type AutomationTriggerType = AutomationTrigger['config']['type'];
737
749
  type AutomationsDeployBody = paths['/api/v1/automations']['put']['requestBody']['content']['application/json'];
738
750
  /** Deploy input without the project ID, which the client injects from its options. */
739
751
  type AutomationsDeployInput = Omit<AutomationsDeployBody, 'projectId'>;
@@ -801,4 +813,4 @@ declare class AutomationsClient extends ApiClient<AutomationsClientOptions> {
801
813
  listRunLogs(runId: string): Promise<AutomationRunLogEntry[]>;
802
814
  }
803
815
 
804
- export { type AutomationRunLogEntry, type AutomationRunStatus, type AutomationRunSummary, type AutomationRunTriggerResponse, type AutomationRunsListResponse, type AutomationSummary, type AutomationTriggerType, AutomationsClient, type AutomationsClientOptions, type AutomationsDeployBody, type AutomationsDeployInput, type AutomationsListResponse };
816
+ export { type AutomationRunLogEntry, type AutomationRunStatus, type AutomationRunSummary, type AutomationRunTriggerResponse, type AutomationRunsListResponse, type AutomationSummary, type AutomationTrigger, type AutomationTriggerType, AutomationsClient, type AutomationsClientOptions, type AutomationsDeployBody, type AutomationsDeployInput, type AutomationsListResponse };
package/dist/index.d.mts CHANGED
@@ -11,6 +11,15 @@ import 'zod';
11
11
  */
12
12
  type EventTriggerConfig<TEvent extends WebhookEventName = WebhookEventName> = {
13
13
  type: TEvent;
14
+ /**
15
+ * Optional CEL ({@link https://github.com/google/cel-spec | Common Expression Language})
16
+ * boolean expression evaluated against `{ input, trigger }` at dispatch time. The automation
17
+ * only runs when it evaluates to `true`; non-matching events are discarded and no run will be recorded.
18
+ * `input` is the event payload; `trigger` is this trigger config.
19
+ *
20
+ * Note: a failure to parse or evaluate the filter will cause a failed automation run to be recorded for diagnostics.
21
+ */
22
+ filter?: string;
14
23
  };
15
24
  /** Trigger configuration for a schedule automation. */
16
25
  type ScheduleTriggerConfig = {
@@ -23,6 +32,15 @@ type ScheduleTriggerConfig = {
23
32
  /** Trigger configuration for an incoming webhook automation. */
24
33
  type IncomingWebhookTriggerConfig = {
25
34
  type: 'incomingWebhook';
35
+ /**
36
+ * Optional CEL ({@link https://github.com/google/cel-spec | Common Expression Language})
37
+ * boolean expression evaluated against `{ input, trigger }` at ingress time. The automation
38
+ * only runs when it evaluates to `true`; uninteresting requests are dropped and no run will be recorded.
39
+ * `input` is the request envelope (`{ method, headers, query, rawBody }`); `trigger` is this trigger config.
40
+ *
41
+ * Note: a failure to parse or evaluate the filter will cause a failed automation run to be recorded for diagnostics.
42
+ */
43
+ filter?: string;
26
44
  };
27
45
  /** Trigger configuration for an automation invocable as an AI tool by Scout. */
28
46
  type AiToolTriggerConfig = {
@@ -30,6 +48,23 @@ type AiToolTriggerConfig = {
30
48
  };
31
49
  /** Canonical authored trigger configuration. */
32
50
  type TriggerConfig = EventTriggerConfig | ScheduleTriggerConfig | IncomingWebhookTriggerConfig | AiToolTriggerConfig;
51
+ /**
52
+ * Triggers that compose freely within a single automation. Events, schedule, and
53
+ * incomingWebhook all run under the automation's machine identity and reduce to a
54
+ * fixed-shape, `eventType`-discriminated run input, so any combination is valid.
55
+ * `aiTool` is excluded — it runs as the invoking caller and must be the sole trigger.
56
+ */
57
+ type ComposableTriggerConfig = EventTriggerConfig | ScheduleTriggerConfig | IncomingWebhookTriggerConfig;
58
+ /**
59
+ * Synthetic run input for a schedule-fired run. Carries an `eventType` discriminant
60
+ * (disjoint from every webhook event name) so scheduled runs join the same
61
+ * discriminated union as event and incoming-webhook runs in the handler.
62
+ */
63
+ type ScheduleRunInput = {
64
+ eventType: 'schedule';
65
+ /** ISO-8601 timestamp of when the schedule fired this run. */
66
+ firedAt: string;
67
+ };
33
68
  /** A plain JSON Schema object (used when the argument contract is authored as JSON Schema directly). */
34
69
  type JsonSchemaObject = Record<string, unknown>;
35
70
  /**
@@ -61,39 +96,40 @@ type AutomationMetadataBase = {
61
96
  permissions?: AutomationPermissions;
62
97
  };
63
98
  /**
64
- * Authored metadata for an event-triggered automation. Parameterize `TEvent`
65
- * with a webhook event name; {@link defineAutomation} then infers the handler's
66
- * `trigger` and `input` from the metadata.
99
+ * Authored metadata for an automation driven by one or more composable triggers
100
+ * (events, schedule, incomingWebhook). {@link defineAutomation} infers the handler's
101
+ * `input` as a single discriminated union across every declared trigger.
102
+ *
103
+ * Composition rules (enforced at deploy time; see the deploy API):
104
+ * - `triggers` must be non-empty;
105
+ * - at most one `schedule` trigger;
106
+ * - at most one `incomingWebhook` trigger;
107
+ * - no duplicate event names.
67
108
  */
68
- type EventAutomationMetadata<TEvent extends WebhookEventName = WebhookEventName> = AutomationMetadataBase & {
69
- trigger: EventTriggerConfig<TEvent>;
70
- };
71
- /** Authored metadata for a schedule-triggered automation. */
72
- type ScheduleAutomationMetadata = AutomationMetadataBase & {
73
- trigger: ScheduleTriggerConfig;
74
- };
75
- /** Authored metadata for an incoming-webhook automation. */
76
- type IncomingWebhookAutomationMetadata = AutomationMetadataBase & {
77
- trigger: IncomingWebhookTriggerConfig;
109
+ type ComposedAutomationMetadata = AutomationMetadataBase & {
110
+ /** One or more triggers this automation subscribes to. Non-empty (enforced as a tuple). */
111
+ triggers: [ComposableTriggerConfig, ...ComposableTriggerConfig[]];
78
112
  };
79
113
  /**
80
114
  * Authored metadata for an automation exposed as an AI tool to Scout.
81
115
  *
82
- * `description` is required (it drives tool selection by the LLM) and `inputSchema`
83
- * declares the tool's argument contract. When `inputSchema` is a zod schema,
84
- * {@link defineAutomation} infers the handler's `input` from it.
116
+ * `aiTool` must be the sole trigger (it runs as the invoking caller, not the machine
117
+ * identity). `description` is required (it drives tool selection by the LLM) and
118
+ * `inputSchema` declares the tool's argument contract. When `inputSchema` is a zod
119
+ * schema, {@link defineAutomation} infers the handler's `input` from it.
85
120
  */
86
121
  type AiToolAutomationMetadata = AutomationMetadataBase & {
87
122
  /** Required for AI tools — the LLM uses it to decide when to call the automation. */
88
123
  description: string;
89
- trigger: AiToolTriggerConfig;
124
+ /** aiTool is exclusive — it must be the only trigger. */
125
+ triggers: [AiToolTriggerConfig];
90
126
  /**
91
127
  * Argument contract surfaced to the LLM. A zod schema or a JSON Schema object.
92
128
  */
93
129
  inputSchema: AiToolInputSchema;
94
130
  };
95
131
  /** Authored metadata declared via {@link defineAutomation}. */
96
- type AutomationMetadata = EventAutomationMetadata | ScheduleAutomationMetadata | IncomingWebhookAutomationMetadata | AiToolAutomationMetadata;
132
+ type AutomationMetadata = ComposedAutomationMetadata | AiToolAutomationMetadata;
97
133
 
98
134
  /**
99
135
  * Per-run Uniform API connection parameters.
@@ -159,9 +195,13 @@ interface AutomationLogger {
159
195
  * @typeParam TTrigger - The authored trigger configuration.
160
196
  */
161
197
  interface AutomationContext<TInput = unknown, TTrigger extends TriggerConfig = TriggerConfig> {
162
- /** The automation's trigger definition. */
198
+ /** The specific trigger that fired this run (one of the automation's declared triggers). */
163
199
  trigger: TTrigger;
164
- /** The input payload for this run (event payload, incoming webhook request, or none for schedule). */
200
+ /**
201
+ * The input payload for this run: the event payload, the incoming-webhook request,
202
+ * or `{ eventType: 'schedule', firedAt }` for a scheduled run. When the automation
203
+ * declares multiple triggers this is a discriminated union — narrow on `input.eventType`.
204
+ */
165
205
  input: TInput;
166
206
  /** Structured logger; entries appear in the run log. */
167
207
  log: AutomationLogger;
@@ -180,11 +220,18 @@ interface AutomationContext<TInput = unknown, TTrigger extends TriggerConfig = T
180
220
  *
181
221
  * @typeParam TInput - The input payload type.
182
222
  * @typeParam TTrigger - The trigger configuration.
223
+ * @typeParam TContextExtras - Extra context guarantees derived from authored metadata, intersected
224
+ * onto the context (see `CredentialsFromAutomationMetadata`). Defaults to no extra guarantees.
183
225
  */
184
- type AutomationHandler<TInput = unknown, TTrigger extends TriggerConfig = TriggerConfig> = (context: AutomationContext<TInput, TTrigger>) => Promise<AutomationResult | void> | AutomationResult | void;
226
+ type AutomationHandler<TInput = unknown, TTrigger extends TriggerConfig = TriggerConfig, TContextExtras = unknown> = (context: AutomationContext<TInput, TTrigger> & TContextExtras) => Promise<AutomationResult | void> | AutomationResult | void;
185
227
 
186
228
  /** HTTP request details passed to an incoming-webhook automation handler. */
187
229
  type IncomingWebhookInput = {
230
+ /**
231
+ * Discriminant so incoming-webhook runs join the same `eventType`-discriminated
232
+ * union as event and schedule runs. Disjoint from every webhook event name.
233
+ */
234
+ eventType: 'incomingWebhook';
188
235
  /** HTTP method of the incoming request (e.g. `POST`). */
189
236
  method: string;
190
237
  /** Normalized request headers (lower-cased keys). */
@@ -200,9 +247,9 @@ type IncomingWebhookInput = {
200
247
  * {@link defineAutomation} wraps a handler to accept this shape.
201
248
  */
202
249
  interface AutomationInvokePayload {
203
- /** The automation's declared trigger configuration. */
250
+ /** The specific trigger that fired this run. */
204
251
  trigger: TriggerConfig;
205
- /** Input for this run. */
252
+ /** Input for this run (event payload, incoming-webhook request, or `{ eventType: 'schedule', firedAt }`). */
206
253
  input: unknown;
207
254
  /**
208
255
  * Per-run Uniform API credentials. Present when the automation has an assigned role,
@@ -219,28 +266,69 @@ interface AutomationInvokePayload {
219
266
  type AutomationInvoker = (payload: AutomationInvokePayload) => Promise<AutomationResult & {
220
267
  logs: AutomationLogEntry[];
221
268
  }>;
269
+ /** True when `T` contains a trigger whose `type` is `K`. */
270
+ type HasTrigger<T extends readonly TriggerConfig[], K> = [Extract<T[number], {
271
+ type: K;
272
+ }>] extends [never] ? false : true;
273
+ /** Union of the webhook event names present in `T` (excludes schedule/incomingWebhook/aiTool). */
274
+ type EventNamesOf<T extends readonly TriggerConfig[]> = Extract<T[number], {
275
+ type: WebhookEventName;
276
+ }>['type'];
222
277
  /**
223
- * Resolves the handler input type from authored metadata: AI-tool arguments (from
224
- * the declared `inputSchema`), event payload, incoming-webhook request details, or
225
- * `unknown` for schedule triggers.
278
+ * The combined handler input for a set of composable triggers: one discriminated
279
+ * union over `eventType` covering every declared event payload, plus a synthetic
280
+ * `schedule` / `incomingWebhook` member when those triggers are present. Every webhook
281
+ * payload already carries a literal `eventType`, and `'schedule'`/`'incomingWebhook'`
282
+ * are disjoint from all event names, so `switch (input.eventType)` narrows cleanly.
283
+ */
284
+ type CombinedRunInput<T extends readonly TriggerConfig[]> = WebhookPayloadFor<EventNamesOf<T>> | (HasTrigger<T, 'schedule'> extends true ? ScheduleRunInput : never) | (HasTrigger<T, 'incomingWebhook'> extends true ? IncomingWebhookInput : never);
285
+ /**
286
+ * Resolves the handler input type from authored metadata: AI-tool arguments (from the
287
+ * declared `inputSchema`) when `aiTool` is the sole trigger, otherwise a single
288
+ * discriminated union across every declared composable trigger.
226
289
  */
227
290
  type InputFromAutomationMetadata<M extends AutomationMetadata> = M extends {
228
- trigger: {
291
+ triggers: readonly [{
229
292
  type: 'aiTool';
230
- };
293
+ }];
294
+ } ? M extends {
231
295
  inputSchema: infer S;
232
- } ? S extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<S> : unknown : M extends {
233
- trigger: infer TTrigger;
234
- } ? TTrigger extends {
235
- type: infer TType;
236
- } ? TType extends WebhookEventName ? WebhookPayloadFor<TType> : TType extends 'incomingWebhook' ? IncomingWebhookInput : unknown : unknown : unknown;
296
+ } ? S extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<S> : unknown : unknown : M extends {
297
+ triggers: infer T extends readonly TriggerConfig[];
298
+ } ? CombinedRunInput<T> : unknown;
237
299
  /**
238
- * Resolves the handler trigger type from authored metadata (the literal
239
- * `metadata.trigger` object).
300
+ * Resolves the handler trigger type from authored metadata: the union of the
301
+ * automation's declared triggers (the *fired* trigger for a run is one of them).
240
302
  */
241
303
  type TriggerFromAutomationMetadata<M extends AutomationMetadata> = M extends {
242
- trigger: infer TTrigger;
243
- } ? TTrigger : TriggerConfig;
304
+ triggers: infer T extends readonly TriggerConfig[];
305
+ } ? T[number] : TriggerConfig;
306
+ /**
307
+ * Whether a run of an automation with metadata `M` is guaranteed per-run Uniform credentials:
308
+ * either it declares `permissions` (so it gets a machine identity and a minted per-run token), or
309
+ * it is an `aiTool` (invoked with the calling user's own credential).
310
+ */
311
+ type RunHasUniformCredentials<M extends AutomationMetadata> = M extends {
312
+ permissions: object;
313
+ } ? true : HasTrigger<TriggersOf<M>, 'aiTool'>;
314
+ /**
315
+ * The credential guarantee intersected onto the handler context: `uniformCredentials` is required
316
+ * (non-optional) when the authored metadata guarantees it, and adds nothing otherwise — an
317
+ * automation with no `permissions` genuinely has no Uniform API access, so `AutomationContext`
318
+ * leaves the property optional there.
319
+ *
320
+ * The runtime upholds this: {@link defineAutomation} refuses to invoke a handler whose metadata
321
+ * promises credentials when the invoke payload arrives without them.
322
+ */
323
+ type CredentialsFromAutomationMetadata<M extends AutomationMetadata> = RunHasUniformCredentials<M> extends true ? {
324
+ uniformCredentials: UniformConnectionParams;
325
+ } : unknown;
326
+ /** The declared triggers of `M`, or the open trigger union when it declares none statically. */
327
+ type TriggersOf<M extends AutomationMetadata> = M extends {
328
+ triggers: infer T extends readonly TriggerConfig[];
329
+ } ? T : readonly TriggerConfig[];
330
+ /** The handler signature implied by authored metadata: input, fired trigger, and credentials. */
331
+ type HandlerFromAutomationMetadata<M extends AutomationMetadata> = AutomationHandler<InputFromAutomationMetadata<M>, TriggerFromAutomationMetadata<M>, CredentialsFromAutomationMetadata<M>>;
244
332
  /** A fully defined automation module: a callable invoke function with authored metadata attached. */
245
333
  type AutomationDefinition<M extends AutomationMetadata = AutomationMetadata> = AutomationInvoker & {
246
334
  metadata: M;
@@ -254,21 +342,32 @@ type AutomationDefinition<M extends AutomationMetadata = AutomationMetadata> = A
254
342
  *
255
343
  * export default defineAutomation({
256
344
  * metadata: {
257
- * name: 'On entry save',
258
- * trigger: { type: 'entry.changed' },
345
+ * name: 'Sync on publish',
346
+ * triggers: [{ type: 'entry.published' }, { type: 'composition.published' }],
259
347
  * },
260
- * handler: async ({ trigger, input, log }) => {
261
- * // trigger.type is 'entry.changed'; input is that event's payload
348
+ * handler: async ({ input, log }) => {
349
+ * // input is a discriminated union; narrow on input.eventType
350
+ * switch (input.eventType) {
351
+ * case 'entry.published': /* input narrowed *\/ break;
352
+ * case 'composition.published': /* input narrowed *\/ break;
353
+ * }
262
354
  * },
263
355
  * });
264
356
  * ```
265
357
  *
358
+ * Authoring is always via `triggers` (an array), even for a single trigger. Composition
359
+ * rules (non-empty; at most one schedule; at most one incomingWebhook; `aiTool` exclusive;
360
+ * no duplicate event names) are enforced at deploy time.
361
+ *
362
+ * When the metadata declares `permissions` (or an `aiTool` trigger), `context.uniformCredentials`
363
+ * is typed as always present, so handlers can construct API clients without a null check.
364
+ *
266
365
  * @param config - Authored metadata and handler implementation.
267
366
  * @returns A callable default export with a `metadata` property.
268
367
  */
269
368
  declare function defineAutomation<const M extends AutomationMetadata>(config: {
270
369
  metadata: M;
271
- handler: AutomationHandler<InputFromAutomationMetadata<M>, TriggerFromAutomationMetadata<M>>;
370
+ handler: HandlerFromAutomationMetadata<M>;
272
371
  }): AutomationDefinition<M>;
273
372
 
274
- export { type AiToolAutomationMetadata, type AiToolInputSchema, type AiToolTriggerConfig, type AutomationContext, type AutomationDefinition, type AutomationHandler, type AutomationInvokePayload, type AutomationInvoker, AutomationLogEntry, type AutomationLogLevel, type AutomationLogger, type AutomationMetadata, type AutomationPermissions, AutomationResult, type EventAutomationMetadata, type EventTriggerConfig, type IncomingWebhookAutomationMetadata, type IncomingWebhookInput, type IncomingWebhookTriggerConfig, type InputFromAutomationMetadata, type JsonSchemaObject, type ScheduleAutomationMetadata, type ScheduleTriggerConfig, type TriggerConfig, type TriggerFromAutomationMetadata, type UniformConnectionParams, defineAutomation };
373
+ export { type AiToolAutomationMetadata, type AiToolInputSchema, type AiToolTriggerConfig, type AutomationContext, type AutomationDefinition, type AutomationHandler, type AutomationInvokePayload, type AutomationInvoker, AutomationLogEntry, type AutomationLogLevel, type AutomationLogger, type AutomationMetadata, type AutomationPermissions, AutomationResult, type ComposableTriggerConfig, type ComposedAutomationMetadata, type CredentialsFromAutomationMetadata, type EventTriggerConfig, type HandlerFromAutomationMetadata, type IncomingWebhookInput, type IncomingWebhookTriggerConfig, type InputFromAutomationMetadata, type JsonSchemaObject, type ScheduleRunInput, type ScheduleTriggerConfig, type TriggerConfig, type TriggerFromAutomationMetadata, type UniformConnectionParams, defineAutomation };
package/dist/index.mjs CHANGED
@@ -18,7 +18,7 @@ function captureLog(logs, level, message) {
18
18
  break;
19
19
  }
20
20
  }
21
- async function runAutomationHandler(handler, payload) {
21
+ async function runAutomationHandler(handler, payload, options = {}) {
22
22
  var _a, _b;
23
23
  const logs = [];
24
24
  const log = {
@@ -34,6 +34,14 @@ async function runAutomationHandler(handler, payload) {
34
34
  if (payload.uniformCredentials) {
35
35
  context.uniformCredentials = payload.uniformCredentials;
36
36
  }
37
+ if (options.requireUniformCredentials && !payload.uniformCredentials) {
38
+ captureLog(
39
+ logs,
40
+ "error",
41
+ "This automation declares permissions but the run received no Uniform credentials, so it was not invoked. Re-deploy the automation to reprovision its identity."
42
+ );
43
+ return { outcome: "failure", logs };
44
+ }
37
45
  try {
38
46
  const result = await handler(context);
39
47
  return { outcome: (_a = result == null ? void 0 : result.outcome) != null ? _a : "success", logs };
@@ -45,8 +53,16 @@ async function runAutomationHandler(handler, payload) {
45
53
  }
46
54
 
47
55
  // src/defineAutomation.ts
56
+ function metadataRequiresUniformCredentials(metadata) {
57
+ if ("permissions" in metadata && metadata.permissions) {
58
+ return true;
59
+ }
60
+ const triggers = "triggers" in metadata ? metadata.triggers : void 0;
61
+ return Array.isArray(triggers) && triggers.some((trigger) => (trigger == null ? void 0 : trigger.type) === "aiTool");
62
+ }
48
63
  function defineAutomation(config) {
49
- const invoker = (payload) => runAutomationHandler(config.handler, payload);
64
+ const requireUniformCredentials = metadataRequiresUniformCredentials(config.metadata);
65
+ const invoker = (payload) => runAutomationHandler(config.handler, payload, { requireUniformCredentials });
50
66
  return Object.assign(invoker, { metadata: config.metadata });
51
67
  }
52
68
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/automations-sdk",
3
- "version": "20.50.2-alpha.167+74e60d5bb7",
3
+ "version": "20.72.3-alpha.23+cbe06f1e8a",
4
4
  "description": "Uniform Automations SDK",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "exports": {
@@ -40,8 +40,8 @@
40
40
  ],
41
41
  "dependencies": {
42
42
  "@standard-schema/spec": "^1.1.0",
43
- "@uniformdev/context": "20.50.2-alpha.167+74e60d5bb7",
44
- "@uniformdev/webhooks": "20.50.2-alpha.167+74e60d5bb7"
43
+ "@uniformdev/context": "20.72.3-alpha.23+cbe06f1e8a",
44
+ "@uniformdev/webhooks": "20.72.3-alpha.23+cbe06f1e8a"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "ai": "^6.0.0",
@@ -56,11 +56,11 @@
56
56
  }
57
57
  },
58
58
  "devDependencies": {
59
- "ai": "6.0.208",
59
+ "ai": "6.0.220",
60
60
  "zod": "4.4.3"
61
61
  },
62
62
  "publishConfig": {
63
63
  "access": "public"
64
64
  },
65
- "gitHead": "74e60d5bb79fe1c4d446e4d3e6edf9f08850be4f"
65
+ "gitHead": "cbe06f1e8a5bb93b0e3cae6b1c8774f21c10506e"
66
66
  }