@automate.ax/api-contract 0.76.0 → 0.77.1

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/src/deployment.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { oc } from "@orpc/contract"
2
2
  import * as z from "zod"
3
+ import { cursorPageOutputSchema, cursorPaginationInputSchema } from "./schemas"
3
4
 
4
5
  /** SDK compatibility version used to select the immutable runtime image. */
5
6
  export const AUTOMATION_SDK_VERSION = "2"
6
7
 
7
- const DEPLOYMENT_STATUS_SCHEMA = z.enum([
8
+ export const deploymentStatusSchema = z.enum([
8
9
  "planning",
9
10
  "awaiting_authorization",
10
11
  "configuring",
@@ -17,7 +18,7 @@ const DEPLOYMENT_STATUS_SCHEMA = z.enum([
17
18
  const DEPLOYMENT_IN_PROGRESS_ERROR = {
18
19
  data: z.object({
19
20
  deploymentId: z.string(),
20
- status: DEPLOYMENT_STATUS_SCHEMA,
21
+ status: deploymentStatusSchema,
21
22
  }),
22
23
  message: "A deployment is already in progress.",
23
24
  status: 409,
@@ -30,8 +31,70 @@ const GIT_SOURCE_SCHEMA = z.object({
30
31
  repositoryUrl: z.string().min(1),
31
32
  })
32
33
 
34
+ const DEPLOYMENT_AUTHORIZATION_SCHEMA = z.object({
35
+ requirements: z
36
+ .object({
37
+ binding: z.string(),
38
+ satisfied: z.boolean(),
39
+ serviceId: z.string(),
40
+ })
41
+ .array(),
42
+ url: z.url(),
43
+ })
44
+
45
+ export const deploymentOutputSchema = z.object({
46
+ authorization: DEPLOYMENT_AUTHORIZATION_SCHEMA.nullable(),
47
+ automations: z
48
+ .object({
49
+ description: z.string(),
50
+ id: z.string(),
51
+ identityKey: z.string(),
52
+ scopes: z
53
+ .object({
54
+ name: z.string().optional(),
55
+ path: z.number().int().nonnegative().array().min(1),
56
+ presentation: z.enum(["collapsed", "expanded", "hidden"]),
57
+ })
58
+ .array(),
59
+ subscriptions: z
60
+ .object({
61
+ config: z.json(),
62
+ eventType: z.string(),
63
+ hookSlot: z.number().int().nonnegative(),
64
+ scopePath: z.number().int().nonnegative().array().default([]),
65
+ })
66
+ .array(),
67
+ })
68
+ .array(),
69
+ createdAt: z.date(),
70
+ failure: z.object({ message: z.string() }).nullable(),
71
+ id: z.string(),
72
+ git: GIT_SOURCE_SCHEMA.nullable(),
73
+ project: z.object({
74
+ id: z.string(),
75
+ name: z.string(),
76
+ organization: z.object({
77
+ id: z.string(),
78
+ name: z.string(),
79
+ }),
80
+ }),
81
+ status: deploymentStatusSchema,
82
+ })
83
+
33
84
  export const deploymentContract = {
34
- cancel: oc.input(z.object({ deploymentId: z.string() })).output(z.void()),
85
+ cancel: oc
86
+ .route({
87
+ method: "DELETE",
88
+ path: "/deployments/{deploymentId}",
89
+ operationId: "cancelDeployment",
90
+ summary: "Cancel deployment",
91
+ description:
92
+ "Cancels a deployment that is planning, awaiting authorization, or configuring.",
93
+ successStatus: 204,
94
+ tags: ["Deployments"],
95
+ })
96
+ .input(z.object({ deploymentId: z.string() }))
97
+ .output(z.void()),
35
98
  create: oc
36
99
  .errors({ DEPLOYMENT_IN_PROGRESS: DEPLOYMENT_IN_PROGRESS_ERROR })
37
100
  .input(
@@ -64,50 +127,62 @@ export const deploymentContract = {
64
127
  }),
65
128
  )
66
129
  .output(z.object({ id: z.string() })),
67
- get: oc.input(z.object({ deploymentId: z.string() })).output(
68
- z.object({
69
- automations: z
70
- .object({
71
- description: z.string(),
72
- id: z.string(),
73
- identityKey: z.string(),
74
- scopes: z
75
- .object({
76
- name: z.string().optional(),
77
- path: z.number().int().nonnegative().array().min(1),
78
- presentation: z.enum(["collapsed", "expanded", "hidden"]),
79
- })
80
- .array(),
81
- subscriptions: z
82
- .object({
83
- config: z.json(),
84
- eventType: z.string(),
85
- hookSlot: z.number().int().nonnegative(),
86
- scopePath: z.number().int().nonnegative().array().default([]),
87
- })
88
- .array(),
130
+ get: oc
131
+ .route({
132
+ method: "GET",
133
+ path: "/deployments/{deploymentId}",
134
+ operationId: "getDeployment",
135
+ summary: "Get deployment",
136
+ description:
137
+ "Returns normalized deployment status, authorization requirements, and planned automations.",
138
+ tags: ["Deployments"],
139
+ })
140
+ .input(z.object({ deploymentId: z.string() }))
141
+ .output(deploymentOutputSchema),
142
+ list: oc
143
+ .route({
144
+ method: "GET",
145
+ path: "/deployments",
146
+ operationId: "listDeployments",
147
+ summary: "List deployments",
148
+ description:
149
+ "Lists deployments visible to the caller, optionally filtered by organization, project, status, or creation time.",
150
+ tags: ["Deployments"],
151
+ })
152
+ .input(
153
+ cursorPaginationInputSchema
154
+ .extend({
155
+ organizationId: z.string().optional(),
156
+ projectId: z.string().optional(),
157
+ since: z.date().optional(),
158
+ status: deploymentStatusSchema.optional(),
159
+ until: z.date().optional(),
89
160
  })
90
- .array(),
91
- createdAt: z.date(),
92
- id: z.string(),
93
- git: GIT_SOURCE_SCHEMA.nullable(),
94
- job: z
95
- .object({
96
- attempts: z.number().int().nonnegative(),
97
- error: z.string().nullable(),
98
- maxAttempts: z.number().int().positive(),
99
- nextRunAt: z.date(),
161
+ .superRefine(({ since, until }, context) => {
162
+ if (since !== undefined && until !== undefined && since > until) {
163
+ context.addIssue({
164
+ code: "custom",
165
+ message: "Since must be before or equal to until.",
166
+ path: ["since"],
167
+ })
168
+ }
100
169
  })
101
- .nullable(),
102
- project: z.object({
103
- id: z.string(),
104
- name: z.string(),
105
- }),
106
- status: DEPLOYMENT_STATUS_SCHEMA,
107
- }),
108
- ),
170
+ .prefault({}),
171
+ )
172
+ .output(cursorPageOutputSchema(deploymentOutputSchema)),
109
173
  redeploy: oc
110
174
  .errors({ DEPLOYMENT_IN_PROGRESS: DEPLOYMENT_IN_PROGRESS_ERROR })
175
+ .route({
176
+ method: "POST",
177
+ path: "/projects/{projectId}/deployments/redeploy",
178
+ operationId: "redeployProject",
179
+ summary: "Redeploy project",
180
+ description:
181
+ "Creates a deployment from the project's active artifact and plans with explicit integration account bindings.",
182
+ successStatus: 201,
183
+ successDescription: "Redeployment created.",
184
+ tags: ["Deployments"],
185
+ })
111
186
  .input(
112
187
  z.object({
113
188
  bindings: z
@@ -0,0 +1,48 @@
1
+ import { oc } from "@orpc/contract"
2
+ import { z } from "zod"
3
+
4
+ export const googleMeetEventsContract = {
5
+ googleMeetPush: oc
6
+ .route({
7
+ method: "POST",
8
+ path: "/events/google-meet",
9
+ operationId: "receiveGoogleMeetPush",
10
+ summary: "Receive a Google Meet push notification",
11
+ description:
12
+ "Receives and authenticates Google Meet CloudEvents delivered by Google Cloud Pub/Sub.",
13
+ tags: ["Events"],
14
+ successStatus: 204,
15
+ })
16
+ .input(
17
+ z.object({
18
+ /** Pub/Sub message containing one encoded Google Workspace CloudEvent. */
19
+ message: z.object({
20
+ /** CloudEvent routing attributes supplied by Pub/Sub. */
21
+ attributes: z.looseObject({
22
+ "ce-datacontenttype": z.literal("application/json"),
23
+ "ce-id": z.string().min(1),
24
+ "ce-source": z.string().min(1),
25
+ "ce-specversion": z.literal("1.0"),
26
+ "ce-subject": z.string().min(1),
27
+ "ce-time": z.iso.datetime({ offset: true }),
28
+ "ce-type": z.string().min(1),
29
+ }),
30
+
31
+ /** Base64-encoded CloudEvent data. */
32
+ data: z.string().min(1),
33
+
34
+ /** Pub/Sub message identifier. */
35
+ messageId: z.string().min(1),
36
+
37
+ /** RFC 3339 time at which Pub/Sub published the notification. */
38
+ publishTime: z.iso.datetime({ offset: true }),
39
+ }),
40
+
41
+ /** Pub/Sub subscription that delivered the message. */
42
+ subscription: z.literal(
43
+ "projects/opkitty/subscriptions/automate-ax-google-meet-push",
44
+ ),
45
+ }),
46
+ )
47
+ .output(z.void()),
48
+ }
@@ -3,6 +3,7 @@ import { asanaEventsContract } from "./asana"
3
3
  import { brevoEventsContract } from "./brevo"
4
4
  import { googleCalendarEventsContract } from "./google-calendar"
5
5
  import { googleFormsEventsContract } from "./google-forms"
6
+ import { googleMeetEventsContract } from "./google-meet"
6
7
  import { gmailEventsContract } from "./gmail"
7
8
  import { githubEventsContract } from "./github"
8
9
  import { linearEventsContract } from "./linear"
@@ -20,6 +21,7 @@ export const eventsContract = {
20
21
  ...brevoEventsContract,
21
22
  ...googleCalendarEventsContract,
22
23
  ...googleFormsEventsContract,
24
+ ...googleMeetEventsContract,
23
25
  ...gmailEventsContract,
24
26
  ...githubEventsContract,
25
27
  ...linearEventsContract,
@@ -0,0 +1,69 @@
1
+ import { oc } from "@orpc/contract"
2
+ import { z } from "zod"
3
+
4
+ export const EXECUTION_DATASET_VERSION = 4
5
+
6
+ export const executionDatasetResourceSchema = z.enum([
7
+ "projects",
8
+ "automations",
9
+ "contexts",
10
+ "context-parents",
11
+ "event-links",
12
+ "events",
13
+ "actions",
14
+ "signal-invocations",
15
+ "signal-coordinators",
16
+ "signal-offers",
17
+ "signal-decisions",
18
+ "logs",
19
+ "outputs",
20
+ "trace-spans",
21
+ ])
22
+
23
+ export const executionDatasetScopeSchema = z.object({
24
+ organizationId: z.string().nullable(),
25
+ projectId: z.string().nullable(),
26
+ since: z.iso.datetime({ offset: true }).nullable(),
27
+ })
28
+
29
+ export const executionDatasetManifestSchema = z.object({
30
+ consistency: z.literal("eventual"),
31
+ profileId: z.string().min(1),
32
+ resources: z
33
+ .object({
34
+ name: executionDatasetResourceSchema,
35
+ url: z.url(),
36
+ })
37
+ .array(),
38
+ schemaVersion: z.literal(EXECUTION_DATASET_VERSION),
39
+ scope: executionDatasetScopeSchema,
40
+ })
41
+
42
+ export type ExecutionDatasetManifest = z.infer<
43
+ typeof executionDatasetManifestSchema
44
+ >
45
+ export type ExecutionDatasetResource = z.infer<
46
+ typeof executionDatasetResourceSchema
47
+ >
48
+ export type ExecutionDatasetScope = z.infer<typeof executionDatasetScopeSchema>
49
+
50
+ export const executionDataContract = {
51
+ manifest: oc
52
+ .route({
53
+ method: "GET",
54
+ path: "/execution-data/manifest",
55
+ operationId: "getExecutionDataManifest",
56
+ summary: "Get execution data manifest",
57
+ description:
58
+ "Returns authenticated Electric shape resources for a validated execution-data scope.",
59
+ tags: ["Execution data"],
60
+ })
61
+ .input(
62
+ z.object({
63
+ organizationId: z.string().optional(),
64
+ projectId: z.string().optional(),
65
+ since: z.iso.datetime({ offset: true }).optional(),
66
+ }),
67
+ )
68
+ .output(executionDatasetManifestSchema),
69
+ }
package/src/index.ts CHANGED
@@ -5,21 +5,50 @@ import { authContract } from "./auth"
5
5
  import { authorizationContract } from "./authorization"
6
6
  import { deploymentContract } from "./deployment"
7
7
  import { eventsContract } from "./events"
8
+ import { executionDataContract } from "./execution-data"
8
9
  import { orgContract } from "./org"
9
10
  import { projectContract } from "./project"
10
11
  import { runtimeContract } from "./runtime"
11
12
 
12
- export { automationExecutionStatusSchema } from "./automation"
13
- export { AUTOMATION_SDK_VERSION } from "./deployment"
13
+ export {
14
+ automationExecutionStatusSchema,
15
+ automationOutputSchema,
16
+ } from "./automation"
17
+ export {
18
+ EXECUTION_DATASET_VERSION,
19
+ executionDatasetManifestSchema,
20
+ executionDatasetResourceSchema,
21
+ executionDatasetScopeSchema,
22
+ type ExecutionDatasetManifest,
23
+ type ExecutionDatasetResource,
24
+ type ExecutionDatasetScope,
25
+ executionDataContract,
26
+ } from "./execution-data"
27
+ export {
28
+ AUTOMATION_SDK_VERSION,
29
+ deploymentOutputSchema,
30
+ deploymentStatusSchema,
31
+ } from "./deployment"
14
32
  export {
15
33
  AUTOMATION_ERROR_CAUSE_DEPTH,
16
34
  automationErrorSchema,
17
35
  type AutomationErrorValue,
18
36
  } from "./errors"
19
- export { integrationAccountOutputSchema } from "./account"
37
+ export {
38
+ integrationAccountOutputSchema,
39
+ integrationAccountRevocationImpactOutputSchema,
40
+ integrationAccountRevocationOutputSchema,
41
+ integrationServiceOutputSchema,
42
+ } from "./account"
20
43
  export {
21
44
  AUTOMATION_INVOCATION_DEFAULT_ENTRYPOINT,
22
45
  AUTOMATION_INVOCATION_RESERVED_ENTRYPOINT_PREFIX,
46
+ AUTOMATION_LOG_MAX_ENTRIES,
47
+ AUTOMATION_LOG_MAX_MESSAGE_LENGTH,
48
+ AUTOMATION_OBSERVABILITY_MAX_ENCODED_BYTES,
49
+ AUTOMATION_OBSERVABILITY_MAX_FIELDS,
50
+ AUTOMATION_TRACE_MAX_NAME_LENGTH,
51
+ AUTOMATION_TRACE_MAX_SPANS,
23
52
  DEFAULT_GATEWAY_MODEL_ID,
24
53
  automationInvocationInputSchema,
25
54
  automationInvocationOutputSchema,
@@ -50,7 +79,12 @@ export {
50
79
  publicOrganizationOutputSchema,
51
80
  } from "./org"
52
81
  export { projectOutputSchema } from "./project"
53
- export { reasonableNameSchema } from "./schemas"
82
+ export {
83
+ cursorPageInfoSchema,
84
+ cursorPageOutputSchema,
85
+ cursorPaginationInputSchema,
86
+ reasonableNameSchema,
87
+ } from "./schemas"
54
88
  export { userOutputSchema } from "./auth"
55
89
  export {
56
90
  managementPermissionStatement,
@@ -61,7 +95,24 @@ export {
61
95
 
62
96
  /** Procedures exposed by the public Node client and OpenAPI document. */
63
97
  export const publicContract = {
98
+ account: accountContract,
99
+ automation: {
100
+ get: automationContract.get,
101
+ list: automationContract.list,
102
+ update: automationContract.update,
103
+ },
64
104
  apiKey: apiKeyContract,
105
+ authorization: {
106
+ get: authorizationContract.get,
107
+ proceed: authorizationContract.proceed,
108
+ },
109
+ deployment: {
110
+ cancel: deploymentContract.cancel,
111
+ get: deploymentContract.get,
112
+ list: deploymentContract.list,
113
+ redeploy: deploymentContract.redeploy,
114
+ },
115
+ executionData: executionDataContract,
65
116
  org: {
66
117
  create: orgContract.create,
67
118
  delete: orgContract.delete,
@@ -87,12 +138,14 @@ export const publicContract = {
87
138
  /** Procedures used by first-party control-plane clients. */
88
139
  export const firstPartyContract = {
89
140
  ...publicContract,
90
- account: accountContract,
91
- automation: automationContract,
141
+ automation: {
142
+ ...publicContract.automation,
143
+ getExecution: automationContract.getExecution,
144
+ listExecutions: automationContract.listExecutions,
145
+ },
92
146
  authorization: {
147
+ ...publicContract.authorization,
93
148
  beginConnection: authorizationContract.beginConnection,
94
- get: authorizationContract.get,
95
- proceed: authorizationContract.proceed,
96
149
  selectAccount: authorizationContract.selectAccount,
97
150
  submitCredentials: authorizationContract.submitCredentials,
98
151
  },
package/src/org.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { oc } from "@orpc/contract"
2
2
  import * as z from "zod"
3
- import { reasonableNameSchema } from "./schemas"
3
+ import {
4
+ cursorPageOutputSchema,
5
+ cursorPaginationInputSchema,
6
+ reasonableNameSchema,
7
+ } from "./schemas"
4
8
 
5
9
  export const organizationRoleSchema = z.enum(["member", "admin", "owner"])
6
10
 
@@ -185,13 +189,13 @@ export const orgContract = {
185
189
  tags: ["Organizations"],
186
190
  })
187
191
  .input(
188
- z
189
- .object({
192
+ cursorPaginationInputSchema
193
+ .extend({
190
194
  query: z.string().min(1).optional(),
191
195
  })
192
- .default({}),
196
+ .prefault({}),
193
197
  )
194
- .output(organizationSummaryOutputSchema.array()),
198
+ .output(cursorPageOutputSchema(organizationSummaryOutputSchema)),
195
199
  remove: oc
196
200
  .route({
197
201
  method: "DELETE",
package/src/project.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { oc } from "@orpc/contract"
2
2
  import * as z from "zod"
3
- import { reasonableNameSchema } from "./schemas"
3
+ import {
4
+ cursorPageOutputSchema,
5
+ cursorPaginationInputSchema,
6
+ reasonableNameSchema,
7
+ } from "./schemas"
4
8
 
5
9
  const TRANSACTION_OUTPUT_SCHEMA = z.object({
6
10
  txid: z.number().int().nonnegative(),
@@ -61,14 +65,14 @@ export const projectContract = {
61
65
  tags: ["Projects"],
62
66
  })
63
67
  .input(
64
- z
65
- .object({
68
+ cursorPaginationInputSchema
69
+ .extend({
66
70
  organizationId: z.string().optional(),
67
71
  query: z.string().min(1).optional(),
68
72
  })
69
- .optional(),
73
+ .prefault({}),
70
74
  )
71
- .output(projectOutputSchema.array()),
75
+ .output(cursorPageOutputSchema(projectOutputSchema)),
72
76
  get: oc
73
77
  .route({
74
78
  method: "GET",
package/src/runtime.ts CHANGED
@@ -12,6 +12,12 @@ export const DEFAULT_GATEWAY_MODEL_ID =
12
12
  "openai/gpt-4.1-nano" satisfies GatewayModelId
13
13
  export const AUTOMATION_INVOCATION_DEFAULT_ENTRYPOINT = "default"
14
14
  export const AUTOMATION_INVOCATION_RESERVED_ENTRYPOINT_PREFIX = "__$"
15
+ export const AUTOMATION_LOG_MAX_ENTRIES = 1_000
16
+ export const AUTOMATION_TRACE_MAX_SPANS = 250
17
+ export const AUTOMATION_OBSERVABILITY_MAX_FIELDS = 64
18
+ export const AUTOMATION_OBSERVABILITY_MAX_ENCODED_BYTES = 64 * 1_024
19
+ export const AUTOMATION_LOG_MAX_MESSAGE_LENGTH = 16_384
20
+ export const AUTOMATION_TRACE_MAX_NAME_LENGTH = 256
15
21
 
16
22
  const OUTCOME_SEQUENCE_SCHEMA = z.number().int().positive()
17
23
  const HOOK_SCOPE_PATH_SCHEMA = z
@@ -20,6 +26,23 @@ const HOOK_SCOPE_PATH_SCHEMA = z
20
26
  .nonnegative()
21
27
  .array()
22
28
  .default([])
29
+ const OBSERVABILITY_FIELDS_SCHEMA = z
30
+ .record(z.string().min(1).max(128), encodableSchema)
31
+ .refine(
32
+ (fields) =>
33
+ Object.keys(fields).length <= AUTOMATION_OBSERVABILITY_MAX_FIELDS,
34
+ `Observability fields may contain at most ${AUTOMATION_OBSERVABILITY_MAX_FIELDS} entries.`,
35
+ )
36
+ const LOG_INDEX_SCHEMA = z
37
+ .number()
38
+ .int()
39
+ .min(0)
40
+ .max(AUTOMATION_LOG_MAX_ENTRIES - 1)
41
+ const TRACE_SPAN_INDEX_SCHEMA = z
42
+ .number()
43
+ .int()
44
+ .min(0)
45
+ .max(AUTOMATION_TRACE_MAX_SPANS - 1)
23
46
 
24
47
  const AUTOMATION_INVOCATION_RUN_AT_SCHEMA = z.union([
25
48
  z.date(),
@@ -685,6 +708,24 @@ export const runtimeContract = {
685
708
  ]),
686
709
  )
687
710
  .output(z.void()),
711
+ completeTraceSpan: oc
712
+ .input(
713
+ z
714
+ .object({
715
+ completedAt: z.date(),
716
+ spanIndex: TRACE_SPAN_INDEX_SCHEMA,
717
+ })
718
+ .and(
719
+ z.union([
720
+ z.object({ status: z.literal("succeeded") }),
721
+ z.object({
722
+ failure: automationErrorSchema,
723
+ status: z.literal("failed"),
724
+ }),
725
+ ]),
726
+ ),
727
+ )
728
+ .output(z.void()),
688
729
  generate: oc
689
730
  .input(RUNTIME_GENERATION_INPUT_SCHEMA)
690
731
  .output(generationResultSchema),
@@ -715,7 +756,7 @@ export const runtimeContract = {
715
756
  )
716
757
  .output(
717
758
  z.object({
718
- connectionId: z.string().min(1),
759
+ connectionMethodId: z.string().min(1),
719
760
  secret: z.record(z.string(), z.unknown()),
720
761
  serviceId: z.string(),
721
762
  }),
@@ -731,6 +772,29 @@ export const runtimeContract = {
731
772
  }),
732
773
  )
733
774
  .output(z.void()),
775
+ sendLog: oc
776
+ .input(
777
+ z.object({
778
+ fields: OBSERVABILITY_FIELDS_SCHEMA.optional(),
779
+ level: z.enum(["debug", "info", "warn", "error"]),
780
+ logIndex: LOG_INDEX_SCHEMA,
781
+ message: z.string().min(1).max(AUTOMATION_LOG_MAX_MESSAGE_LENGTH),
782
+ spanIndex: TRACE_SPAN_INDEX_SCHEMA.optional(),
783
+ timestamp: z.date(),
784
+ }),
785
+ )
786
+ .output(z.void()),
787
+ startTraceSpan: oc
788
+ .input(
789
+ z.object({
790
+ attributes: OBSERVABILITY_FIELDS_SCHEMA.optional(),
791
+ name: z.string().min(1).max(AUTOMATION_TRACE_MAX_NAME_LENGTH),
792
+ parentSpanIndex: TRACE_SPAN_INDEX_SCHEMA.optional(),
793
+ spanIndex: TRACE_SPAN_INDEX_SCHEMA,
794
+ startedAt: z.date(),
795
+ }),
796
+ )
797
+ .output(z.void()),
734
798
  sendEmail: oc
735
799
  .input(
736
800
  z
package/src/schemas.ts CHANGED
@@ -1,3 +1,25 @@
1
1
  import * as z from "zod"
2
2
 
3
+ export const cursorPaginationInputSchema = z.object({
4
+ cursor: z.string().min(1).optional(),
5
+ limit: z.number().int().min(1).max(100).default(50),
6
+ })
7
+
8
+ export const cursorPageInfoSchema = z.object({
9
+ hasMore: z.boolean(),
10
+ nextCursor: z.string().nullable(),
11
+ })
12
+
13
+ /**
14
+ * Builds the common cursor-paginated collection response.
15
+ *
16
+ * @param itemSchema - Schema for one collection item.
17
+ */
18
+ export function cursorPageOutputSchema<T extends z.ZodType>(itemSchema: T) {
19
+ return z.object({
20
+ items: itemSchema.array(),
21
+ pageInfo: cursorPageInfoSchema,
22
+ })
23
+ }
24
+
3
25
  export const reasonableNameSchema = z.string().min(1).max(255).trim()