@automate.ax/api-contract 0.80.0 → 0.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runtime.js CHANGED
@@ -15,12 +15,7 @@ export const AUTOMATION_OBSERVABILITY_MAX_ENCODED_BYTES = 64 * 1_024;
15
15
  export const AUTOMATION_LOG_MAX_MESSAGE_LENGTH = 16_384;
16
16
  export const AUTOMATION_TRACE_MAX_NAME_LENGTH = 256;
17
17
  const OUTCOME_SEQUENCE_SCHEMA = z.number().int().positive();
18
- const HOOK_SCOPE_PATH_SCHEMA = z
19
- .number()
20
- .int()
21
- .nonnegative()
22
- .array()
23
- .default([]);
18
+ const HOOK_SCOPE_PATH_SCHEMA = z.number().int().nonnegative().array();
24
19
  const OBSERVABILITY_FIELDS_SCHEMA = z
25
20
  .record(z.string().min(1).max(128), encodableSchema)
26
21
  .refine((fields) => Object.keys(fields).length <= AUTOMATION_OBSERVABILITY_MAX_FIELDS, `Observability fields may contain at most ${AUTOMATION_OBSERVABILITY_MAX_FIELDS} entries.`);
@@ -98,8 +93,55 @@ export const automationInvocationInputSchema = z
98
93
  }),
99
94
  ]))
100
95
  .and(automationInvocationScheduleSchema);
96
+ const SIGNAL_DERIVATION_NODE_SCHEMA = z.discriminatedUnion("type", [
97
+ z.object({
98
+ id: z.string().min(1),
99
+ source: z.enum(["action", "event", "signal"]),
100
+ type: z.literal("source"),
101
+ }),
102
+ z.object({
103
+ inputs: z.number().int().nonnegative().array().min(1),
104
+ property: z.string(),
105
+ type: z.literal("property"),
106
+ }),
107
+ z.object({
108
+ inputs: z.number().int().nonnegative().array().min(1),
109
+ type: z.literal("transform"),
110
+ }),
111
+ ]);
112
+ /** Compact concrete derivation graph persisted for one durable consumer. */
113
+ export const signalDerivationSchema = z
114
+ .object({
115
+ nodes: SIGNAL_DERIVATION_NODE_SCHEMA.array().min(1),
116
+ roots: z.number().int().nonnegative().array().min(1),
117
+ })
118
+ .superRefine(({ nodes, roots }, context) => {
119
+ for (const [index, node] of nodes.entries()) {
120
+ if (node.type === "source")
121
+ continue;
122
+ for (const input of node.inputs) {
123
+ if (input >= index) {
124
+ context.addIssue({
125
+ code: "custom",
126
+ message: "Derivation inputs must reference preceding nodes.",
127
+ path: ["nodes", index, "inputs"],
128
+ });
129
+ }
130
+ }
131
+ }
132
+ for (const [index, root] of roots.entries()) {
133
+ if (root >= nodes.length) {
134
+ context.addIssue({
135
+ code: "custom",
136
+ message: "Derivation roots must reference an existing node.",
137
+ path: ["roots", index],
138
+ });
139
+ }
140
+ }
141
+ });
101
142
  const ACTION_INVOCATION_BASE_SCHEMA = z.object({
102
143
  actionDependencyIds: z.string().array(),
144
+ derivation: signalDerivationSchema.nullable(),
103
145
  description: z.string().nullable(),
104
146
  eventDependencyIds: z.string().array(),
105
147
  inputHash: z.string(),
@@ -147,13 +189,16 @@ const ACTION_RUN_INVOCATION_SCHEMA = z.union([
147
189
  status: z.literal("succeeded"),
148
190
  }),
149
191
  ]);
150
- const SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA = z.object({
192
+ const SIGNAL_DEPENDENCIES_SCHEMA = z.object({
151
193
  actionDependencyIds: z.string().array(),
152
194
  eventDependencyIds: z.string().array(),
153
195
  scopePath: HOOK_SCOPE_PATH_SCHEMA,
154
196
  signalDependencyIds: z.string().array(),
155
197
  slot: z.number().int().nonnegative(),
156
198
  });
199
+ const SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA = SIGNAL_DEPENDENCIES_SCHEMA.extend({
200
+ derivation: signalDerivationSchema.nullable(),
201
+ });
157
202
  const COORDINATION_PRIMARY_POSITION_SCHEMA = z.enum(["first", "last"]);
158
203
  const COORDINATION_DURATION_SCHEMA = z.union([
159
204
  z.string().min(1),
@@ -253,14 +298,14 @@ const FUNNEL_OFFER_SCHEMA = SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA.extend({
253
298
  }
254
299
  });
255
300
  const RACE_OFFER_BASE_SCHEMA = SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA.extend({
256
- cohortActionDependencyIds: z.string().array().default([]),
257
- cohortEventDependencyIds: z.string().array().default([]),
258
- cohortOrigins: z.string().array().default([]),
259
- cohortSignalDependencyIds: z.string().array().default([]),
301
+ cohortActionDependencyIds: z.string().array(),
302
+ cohortEventDependencyIds: z.string().array(),
303
+ cohortOrigins: z.string().array(),
304
+ cohortSignalDependencyIds: z.string().array(),
260
305
  inputOrigins: z.string().array().array().min(2),
261
306
  outcomeSeq: OUTCOME_SEQUENCE_SCHEMA,
262
307
  policy: z.literal("race"),
263
- scopeOrigins: z.string().array().default([]),
308
+ scopeOrigins: z.string().array(),
264
309
  selectedIndex: z.number().int().nonnegative(),
265
310
  });
266
311
  const RACE_OFFER_SCHEMA = z
@@ -554,25 +599,9 @@ const RUNTIME_GENERATION_INPUT_SCHEMA = z.union([
554
599
  * @param primaryPosition - Optional inherited-parent precedence.
555
600
  */
556
601
  export async function hashSignalCoordinatorConfiguration(definition, primaryPosition) {
557
- const definitionEntries = typeof definition === "object" &&
558
- definition !== null &&
559
- !Array.isArray(definition)
560
- ? Object.entries(definition)
561
- : undefined;
562
- const policy = definitionEntries?.find(([key]) => key === "policy")?.[1];
563
- // Existing coordinators were hashed with `strategy` and implicit primary
564
- // positions for race and fan-out. Preserve that identity while the runtime
565
- // uses the clearer policy vocabulary and no longer overloads primary state.
566
- const persistedDefinition = definitionEntries
567
- ? Object.fromEntries(definitionEntries.map(([key, value]) => [
568
- key === "policy" ? "strategy" : key,
569
- value,
570
- ]))
571
- : definition;
572
602
  return await sha256Base64Url(stableStringify({
573
- definitionHash: await sha256Base64Url(stableStringify(persistedDefinition)),
574
- primaryPosition: primaryPosition ??
575
- (policy === "fanout" || policy === "race" ? "first" : null),
603
+ definitionHash: await sha256Base64Url(stableStringify(definition)),
604
+ primaryPosition: primaryPosition ?? null,
576
605
  }));
577
606
  }
578
607
  /**
@@ -589,10 +618,10 @@ async function sha256Base64Url(value) {
589
618
  export const runtimeContract = {
590
619
  commit: oc
591
620
  .input(z.object({
592
- actionInvocations: ACTION_INVOCATION_SCHEMA.array().default([]),
593
- coordinationOffers: COORDINATION_OFFER_SCHEMA.array().default([]),
594
- settled: z.boolean().default(true),
595
- signalInvocations: SIGNAL_INVOCATION_SCHEMA.array().default([]),
621
+ actionInvocations: ACTION_INVOCATION_SCHEMA.array(),
622
+ coordinationOffers: COORDINATION_OFFER_SCHEMA.array(),
623
+ settled: z.boolean(),
624
+ signalInvocations: SIGNAL_INVOCATION_SCHEMA.array(),
596
625
  }))
597
626
  .output(z.void()),
598
627
  completeAction: oc
@@ -645,7 +674,7 @@ export const runtimeContract = {
645
674
  targetAction: TARGET_ACTION_SCHEMA.optional(),
646
675
  })),
647
676
  loadValues: oc
648
- .input(SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA.omit({
677
+ .input(SIGNAL_DEPENDENCIES_SCHEMA.omit({
649
678
  scopePath: true,
650
679
  slot: true,
651
680
  }))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automate.ax/api-contract",
3
- "version": "0.80.0",
3
+ "version": "0.82.0",
4
4
  "description": "Public oRPC contract for the Automate.ax API.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@ai-sdk/gateway": "^4.0.46",
33
- "@automate.ax/codec": "0.80.0",
33
+ "@automate.ax/codec": "0.82.0",
34
34
  "@orpc/contract": "1.15.0",
35
35
  "fast-json-stable-stringify": "^2.1.0",
36
36
  "zod": "^4.3.6"
@@ -1,7 +1,7 @@
1
1
  import { oc } from "@orpc/contract"
2
2
  import { z } from "zod"
3
3
 
4
- export const EXECUTION_DATASET_VERSION = 4
4
+ export const EXECUTION_DATASET_VERSION = 5
5
5
 
6
6
  export const executionDatasetResourceSchema = z.enum([
7
7
  "projects",
package/src/org.ts CHANGED
@@ -32,10 +32,12 @@ export const organizationSummaryOutputSchema = z.object({
32
32
  pendingInvitationCount: z.number(),
33
33
  projectCount: z.number(),
34
34
  activeSubscription: activeSubscriptionOutputSchema.nullable(),
35
+ executionRetentionDays: z.number().int().positive(),
35
36
  plan: z.enum(["free", "pro", "enterprise"]),
36
37
  limits: z.object({
37
38
  aiSpendUsd: z.number(),
38
39
  emailSends: z.number(),
40
+ executionRetentionDays: z.number().int().positive(),
39
41
  projects: z.number(),
40
42
  seats: z.number(),
41
43
  }),
@@ -225,10 +227,23 @@ export const orgContract = {
225
227
  tags: ["Organizations"],
226
228
  })
227
229
  .input(
228
- z.object({
229
- organizationId: z.string(),
230
- name: reasonableNameSchema,
231
- }),
230
+ z
231
+ .object({
232
+ executionRetentionDays: z
233
+ .number()
234
+ .int()
235
+ .positive()
236
+ .nullable()
237
+ .optional(),
238
+ organizationId: z.string(),
239
+ name: reasonableNameSchema.optional(),
240
+ })
241
+ .refine(
242
+ (input) =>
243
+ input.executionRetentionDays !== undefined ||
244
+ input.name !== undefined,
245
+ "Provide an organization setting to update.",
246
+ ),
232
247
  )
233
248
  .output(z.void()),
234
249
  }
package/src/runtime.ts CHANGED
@@ -21,12 +21,7 @@ export const AUTOMATION_LOG_MAX_MESSAGE_LENGTH = 16_384
21
21
  export const AUTOMATION_TRACE_MAX_NAME_LENGTH = 256
22
22
 
23
23
  const OUTCOME_SEQUENCE_SCHEMA = z.number().int().positive()
24
- const HOOK_SCOPE_PATH_SCHEMA = z
25
- .number()
26
- .int()
27
- .nonnegative()
28
- .array()
29
- .default([])
24
+ const HOOK_SCOPE_PATH_SCHEMA = z.number().int().nonnegative().array()
30
25
  const OBSERVABILITY_FIELDS_SCHEMA = z
31
26
  .record(z.string().min(1).max(128), encodableSchema)
32
27
  .refine(
@@ -115,8 +110,59 @@ export const automationInvocationInputSchema = z
115
110
  )
116
111
  .and(automationInvocationScheduleSchema)
117
112
 
113
+ const SIGNAL_DERIVATION_NODE_SCHEMA = z.discriminatedUnion("type", [
114
+ z.object({
115
+ id: z.string().min(1),
116
+ source: z.enum(["action", "event", "signal"]),
117
+ type: z.literal("source"),
118
+ }),
119
+ z.object({
120
+ inputs: z.number().int().nonnegative().array().min(1),
121
+ property: z.string(),
122
+ type: z.literal("property"),
123
+ }),
124
+ z.object({
125
+ inputs: z.number().int().nonnegative().array().min(1),
126
+ type: z.literal("transform"),
127
+ }),
128
+ ])
129
+
130
+ /** Compact concrete derivation graph persisted for one durable consumer. */
131
+ export const signalDerivationSchema = z
132
+ .object({
133
+ nodes: SIGNAL_DERIVATION_NODE_SCHEMA.array().min(1),
134
+ roots: z.number().int().nonnegative().array().min(1),
135
+ })
136
+ .superRefine(({ nodes, roots }, context) => {
137
+ for (const [index, node] of nodes.entries()) {
138
+ if (node.type === "source") continue
139
+ for (const input of node.inputs) {
140
+ if (input >= index) {
141
+ context.addIssue({
142
+ code: "custom",
143
+ message: "Derivation inputs must reference preceding nodes.",
144
+ path: ["nodes", index, "inputs"],
145
+ })
146
+ }
147
+ }
148
+ }
149
+ for (const [index, root] of roots.entries()) {
150
+ if (root >= nodes.length) {
151
+ context.addIssue({
152
+ code: "custom",
153
+ message: "Derivation roots must reference an existing node.",
154
+ path: ["roots", index],
155
+ })
156
+ }
157
+ }
158
+ })
159
+
160
+ /** Persisted source, property, and opaque transform derivation graph. */
161
+ export type SignalDerivation = z.infer<typeof signalDerivationSchema>
162
+
118
163
  const ACTION_INVOCATION_BASE_SCHEMA = z.object({
119
164
  actionDependencyIds: z.string().array(),
165
+ derivation: signalDerivationSchema.nullable(),
120
166
  description: z.string().nullable(),
121
167
  eventDependencyIds: z.string().array(),
122
168
  inputHash: z.string(),
@@ -168,7 +214,7 @@ const ACTION_RUN_INVOCATION_SCHEMA = z.union([
168
214
  }),
169
215
  ])
170
216
 
171
- const SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA = z.object({
217
+ const SIGNAL_DEPENDENCIES_SCHEMA = z.object({
172
218
  actionDependencyIds: z.string().array(),
173
219
  eventDependencyIds: z.string().array(),
174
220
  scopePath: HOOK_SCOPE_PATH_SCHEMA,
@@ -176,6 +222,12 @@ const SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA = z.object({
176
222
  slot: z.number().int().nonnegative(),
177
223
  })
178
224
 
225
+ const SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA = SIGNAL_DEPENDENCIES_SCHEMA.extend(
226
+ {
227
+ derivation: signalDerivationSchema.nullable(),
228
+ },
229
+ )
230
+
179
231
  const COORDINATION_PRIMARY_POSITION_SCHEMA = z.enum(["first", "last"])
180
232
  const COORDINATION_DURATION_SCHEMA = z.union([
181
233
  z.string().min(1),
@@ -286,14 +338,14 @@ const FUNNEL_OFFER_SCHEMA = SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA.extend({
286
338
  })
287
339
 
288
340
  const RACE_OFFER_BASE_SCHEMA = SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA.extend({
289
- cohortActionDependencyIds: z.string().array().default([]),
290
- cohortEventDependencyIds: z.string().array().default([]),
291
- cohortOrigins: z.string().array().default([]),
292
- cohortSignalDependencyIds: z.string().array().default([]),
341
+ cohortActionDependencyIds: z.string().array(),
342
+ cohortEventDependencyIds: z.string().array(),
343
+ cohortOrigins: z.string().array(),
344
+ cohortSignalDependencyIds: z.string().array(),
293
345
  inputOrigins: z.string().array().array().min(2),
294
346
  outcomeSeq: OUTCOME_SEQUENCE_SCHEMA,
295
347
  policy: z.literal("race"),
296
- scopeOrigins: z.string().array().default([]),
348
+ scopeOrigins: z.string().array(),
297
349
  selectedIndex: z.number().int().nonnegative(),
298
350
  })
299
351
 
@@ -631,32 +683,10 @@ export async function hashSignalCoordinatorConfiguration(
631
683
  definition: unknown,
632
684
  primaryPosition?: "first" | "last",
633
685
  ) {
634
- const definitionEntries =
635
- typeof definition === "object" &&
636
- definition !== null &&
637
- !Array.isArray(definition)
638
- ? Object.entries(definition)
639
- : undefined
640
- const policy = definitionEntries?.find(([key]) => key === "policy")?.[1]
641
- // Existing coordinators were hashed with `strategy` and implicit primary
642
- // positions for race and fan-out. Preserve that identity while the runtime
643
- // uses the clearer policy vocabulary and no longer overloads primary state.
644
- const persistedDefinition = definitionEntries
645
- ? Object.fromEntries(
646
- definitionEntries.map(([key, value]) => [
647
- key === "policy" ? "strategy" : key,
648
- value,
649
- ]),
650
- )
651
- : definition
652
686
  return await sha256Base64Url(
653
687
  stableStringify({
654
- definitionHash: await sha256Base64Url(
655
- stableStringify(persistedDefinition),
656
- ),
657
- primaryPosition:
658
- primaryPosition ??
659
- (policy === "fanout" || policy === "race" ? "first" : null),
688
+ definitionHash: await sha256Base64Url(stableStringify(definition)),
689
+ primaryPosition: primaryPosition ?? null,
660
690
  }),
661
691
  )
662
692
  }
@@ -683,10 +713,10 @@ export const runtimeContract = {
683
713
  commit: oc
684
714
  .input(
685
715
  z.object({
686
- actionInvocations: ACTION_INVOCATION_SCHEMA.array().default([]),
687
- coordinationOffers: COORDINATION_OFFER_SCHEMA.array().default([]),
688
- settled: z.boolean().default(true),
689
- signalInvocations: SIGNAL_INVOCATION_SCHEMA.array().default([]),
716
+ actionInvocations: ACTION_INVOCATION_SCHEMA.array(),
717
+ coordinationOffers: COORDINATION_OFFER_SCHEMA.array(),
718
+ settled: z.boolean(),
719
+ signalInvocations: SIGNAL_INVOCATION_SCHEMA.array(),
690
720
  }),
691
721
  )
692
722
  .output(z.void()),
@@ -749,7 +779,7 @@ export const runtimeContract = {
749
779
  ),
750
780
  loadValues: oc
751
781
  .input(
752
- SIGNAL_INVOCATION_DEPENDENCIES_SCHEMA.omit({
782
+ SIGNAL_DEPENDENCIES_SCHEMA.omit({
753
783
  scopePath: true,
754
784
  slot: true,
755
785
  }),