@shipfox/api-agent-access-dto 21.1.0 → 21.2.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/api-agent-access-dto",
3
3
  "license": "MIT",
4
- "version": "21.1.0",
4
+ "version": "21.2.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
package/src/index.ts CHANGED
@@ -116,6 +116,23 @@ export {
116
116
  listWorkflowRunJobExplanationsResultJsonSchema,
117
117
  listWorkflowRunJobExplanationsResultSchema,
118
118
  } from './schemas/workflow-diagnostics.js';
119
+ export {
120
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_LIMIT,
121
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX,
122
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES,
123
+ type GetExecutionTriggerEventInputDto,
124
+ type GetExecutionTriggerEventResultDto,
125
+ getExecutionTriggerEventInputJsonSchema,
126
+ getExecutionTriggerEventInputSchema,
127
+ getExecutionTriggerEventResultJsonSchema,
128
+ getExecutionTriggerEventResultSchema,
129
+ type ListExecutionTriggerEventsInputDto,
130
+ type ListExecutionTriggerEventsResultDto,
131
+ listExecutionTriggerEventsInputJsonSchema,
132
+ listExecutionTriggerEventsInputSchema,
133
+ listExecutionTriggerEventsResultJsonSchema,
134
+ listExecutionTriggerEventsResultSchema,
135
+ } from './schemas/workflow-execution-events.js';
119
136
  export {
120
137
  AGENT_ACCESS_WORKFLOW_ATTEMPT_MAX,
121
138
  AGENT_ACCESS_WORKFLOW_EXECUTION_COUNT_MAX,
@@ -0,0 +1,43 @@
1
+ import {getTriggerEventResultJsonSchema, getTriggerEventResultSchema} from './diagnostic-tools.js';
2
+
3
+ const eventId = '00000000-0000-4000-8000-000000000001';
4
+
5
+ describe('diagnostic agent-access schemas', () => {
6
+ test('accepts filtered trigger decisions in runtime and JSON schemas', () => {
7
+ const result = {
8
+ id: eventId,
9
+ origin: 'integration',
10
+ provider: 'github',
11
+ source: 'github',
12
+ event: 'push',
13
+ outcome: 'discarded',
14
+ matched_count: 0,
15
+ connection_id: null,
16
+ connection_name: null,
17
+ replay_of_event_id: null,
18
+ received_at: '2026-09-04T12:00:00.000Z',
19
+ processed_at: '2026-09-04T12:00:01.000Z',
20
+ payload_preview: '{}',
21
+ decisions: [
22
+ {
23
+ id: '00000000-0000-4000-8000-000000000002',
24
+ subscription_kind: 'trigger',
25
+ outcome: 'filtered',
26
+ reason: null,
27
+ workflow_definition_id: '00000000-0000-4000-8000-000000000003',
28
+ project_id: '00000000-0000-4000-8000-000000000004',
29
+ workflow_run_id: null,
30
+ job_id: null,
31
+ },
32
+ ],
33
+ decisions_total_count: 1,
34
+ replays: [],
35
+ replays_total_count: 0,
36
+ };
37
+
38
+ expect(getTriggerEventResultSchema.safeParse(result).success).toBe(true);
39
+ expect(
40
+ getTriggerEventResultJsonSchema.properties.decisions.items.properties.outcome.enum,
41
+ ).toContain('filtered');
42
+ });
43
+ });
@@ -28,7 +28,13 @@ export type GetTriggerEventFacetsInputDto = z.infer<typeof getTriggerEventFacets
28
28
 
29
29
  const triggerOriginSchema = z.enum(['integration', 'manual', 'cron', 'dev']);
30
30
  const triggerOutcomeSchema = z.enum(['received', 'routed', 'discarded', 'failed', 'errored']);
31
- const triggerDecisionOutcomeSchema = z.enum(['triggered', 'filter-error', 'dispatch-error']);
31
+ const triggerDecisionOutcomeSchema = z.enum([
32
+ 'triggered',
33
+ 'filtered',
34
+ 'filter-error',
35
+ 'dispatch-error',
36
+ 'rejected',
37
+ ]);
32
38
  const triggerDecisionSchema = z
33
39
  .object({
34
40
  id: idSchema,
@@ -135,7 +141,10 @@ const triggerDecisionJsonSchema = {
135
141
  properties: {
136
142
  id: uuid,
137
143
  subscription_kind: {type: 'string', enum: ['trigger', 'listener', 'dev']},
138
- outcome: {type: 'string', enum: ['triggered', 'filter-error', 'dispatch-error']},
144
+ outcome: {
145
+ type: 'string',
146
+ enum: ['triggered', 'filtered', 'filter-error', 'dispatch-error', 'rejected'],
147
+ },
139
148
  reason: nullable(text),
140
149
  workflow_definition_id: nullable(uuid),
141
150
  project_id: nullable(uuid),
@@ -0,0 +1,126 @@
1
+ import {
2
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_LIMIT,
3
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX,
4
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES,
5
+ getExecutionTriggerEventInputJsonSchema,
6
+ getExecutionTriggerEventInputSchema,
7
+ getExecutionTriggerEventResultJsonSchema,
8
+ getExecutionTriggerEventResultSchema,
9
+ listExecutionTriggerEventsInputSchema,
10
+ listExecutionTriggerEventsResultJsonSchema,
11
+ listExecutionTriggerEventsResultSchema,
12
+ } from './workflow-execution-events.js';
13
+
14
+ const jobId = '00000000-0000-4000-8000-000000000001';
15
+ const executionId = '00000000-0000-4000-8000-000000000002';
16
+ const eventRef = '00000000-0000-4000-8000-000000000003';
17
+ const deliveryId = '00000000-0000-4000-8000-000000000004';
18
+ const receivedAt = '2026-08-31T12:00:00.000Z';
19
+
20
+ describe('workflow execution event Agent Access schemas', () => {
21
+ test('accepts bounded summaries and serialized JSON detail', () => {
22
+ expect(listExecutionTriggerEventsResultSchema.safeParse(listResult()).success).toBe(true);
23
+ expect(
24
+ getExecutionTriggerEventResultSchema.safeParse({
25
+ ...summary(),
26
+ payload_preview: '{"action":"opened"}',
27
+ }).success,
28
+ ).toBe(true);
29
+ });
30
+
31
+ test('requires non-empty event references and preserves long lookup keys', () => {
32
+ const longEventRef = `${eventRef}${'x'.repeat(512)}`;
33
+
34
+ expect(
35
+ getExecutionTriggerEventInputSchema.safeParse({
36
+ job_id: jobId,
37
+ execution_id: executionId,
38
+ event_ref: longEventRef,
39
+ }).success,
40
+ ).toBe(true);
41
+ expect(
42
+ getExecutionTriggerEventInputSchema.safeParse({
43
+ job_id: jobId,
44
+ execution_id: executionId,
45
+ event_ref: '',
46
+ }).success,
47
+ ).toBe(false);
48
+ expect(getExecutionTriggerEventInputJsonSchema.properties.event_ref).toMatchObject({
49
+ minLength: 1,
50
+ });
51
+ expect(
52
+ getExecutionTriggerEventResultSchema.safeParse({
53
+ ...summary(),
54
+ event_ref: longEventRef,
55
+ payload_preview: null,
56
+ }).success,
57
+ ).toBe(true);
58
+ });
59
+
60
+ test('uses the producer page default and rejects workspace-level input', () => {
61
+ expect(
62
+ listExecutionTriggerEventsInputSchema.parse({job_id: jobId, execution_id: executionId}),
63
+ ).toMatchObject({limit: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_LIMIT});
64
+ expect(
65
+ listExecutionTriggerEventsInputSchema.safeParse({
66
+ job_id: jobId,
67
+ execution_id: executionId,
68
+ workspace_id: '00000000-0000-4000-8000-000000000005',
69
+ }).success,
70
+ ).toBe(false);
71
+ });
72
+
73
+ test('mirrors page, metadata, and preview bounds in JSON schemas', () => {
74
+ expect(listExecutionTriggerEventsResultJsonSchema.properties.trigger_events).toMatchObject({
75
+ type: 'array',
76
+ maxItems: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX,
77
+ });
78
+ expect(getExecutionTriggerEventResultJsonSchema.properties.payload_preview).toMatchObject({
79
+ anyOf: [
80
+ {
81
+ type: 'string',
82
+ maxLength: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES,
83
+ contentMediaType: 'application/json',
84
+ },
85
+ {type: 'null'},
86
+ ],
87
+ });
88
+ });
89
+
90
+ test('rejects clipped or invalid payload previews', () => {
91
+ const invalidPreviews = [
92
+ 'not-json',
93
+ `{"body":"${'x'.repeat(AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES)}"}`,
94
+ ];
95
+ for (const payload_preview of invalidPreviews) {
96
+ expect(
97
+ getExecutionTriggerEventResultSchema.safeParse({...summary(), payload_preview}).success,
98
+ ).toBe(false);
99
+ }
100
+ });
101
+ });
102
+
103
+ function summary() {
104
+ return {
105
+ event_ref: eventRef,
106
+ delivery_id: deliveryId,
107
+ source: 'github',
108
+ event: 'push',
109
+ disposition: 'fire' as const,
110
+ outcome: 'consumed' as const,
111
+ outcome_reason: null,
112
+ received_at: receivedAt,
113
+ stored_payload_bytes: 32,
114
+ normalized_event_bytes: 128,
115
+ };
116
+ }
117
+
118
+ function listResult() {
119
+ return {
120
+ job_id: jobId,
121
+ execution_id: executionId,
122
+ trigger_events: [summary()],
123
+ next_cursor: null,
124
+ total: 1,
125
+ };
126
+ }
@@ -0,0 +1,217 @@
1
+ import {z} from 'zod';
2
+ import type {AgentAccessObjectSchema} from './envelope.js';
3
+ import {AGENT_ACCESS_PAGE_LIMIT_MAX, AGENT_ACCESS_TEXT_MAX_BYTES} from './paged-tools.js';
4
+ import {dateTimeSchema, idSchema, utf8CappedString} from './primitives.js';
5
+
6
+ /** Default page size for one execution's listener-event history. */
7
+ export const AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_LIMIT = 25;
8
+
9
+ /** Maximum number of execution listener-event summaries in one page. */
10
+ export const AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX = AGENT_ACCESS_PAGE_LIMIT_MAX;
11
+
12
+ /** Maximum serialized UTF-8 size of one untrusted payload preview. */
13
+ export const AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES = 16 * 1024;
14
+
15
+ const textSchema = utf8CappedString(AGENT_ACCESS_TEXT_MAX_BYTES);
16
+ const payloadPreviewSchema = utf8CappedString(
17
+ AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES,
18
+ ).refine(isSerializedJson, {message: 'Payload preview must be serialized JSON'});
19
+
20
+ const executionTriggerEventDispositionSchema = z.enum(['fire', 'resolve']);
21
+ const executionTriggerEventOutcomeSchema = z.enum([
22
+ 'pending',
23
+ 'consumed',
24
+ 'honored',
25
+ 'rejected',
26
+ 'abandoned',
27
+ ]);
28
+ const executionTriggerEventOutcomeReasonSchema = z
29
+ .enum(['payload_too_large', 'until', 'timeout', 'max_executions', 'cancelled'])
30
+ .nullable();
31
+ const eventRefSchema = z.string().min(1);
32
+
33
+ const executionTriggerEventSummarySchema = z
34
+ .object({
35
+ event_ref: eventRefSchema,
36
+ delivery_id: textSchema,
37
+ source: textSchema,
38
+ event: textSchema,
39
+ disposition: executionTriggerEventDispositionSchema,
40
+ outcome: executionTriggerEventOutcomeSchema,
41
+ outcome_reason: executionTriggerEventOutcomeReasonSchema,
42
+ received_at: dateTimeSchema,
43
+ stored_payload_bytes: z.number().int().nonnegative(),
44
+ normalized_event_bytes: z.number().int().nonnegative(),
45
+ })
46
+ .strict();
47
+
48
+ export const listExecutionTriggerEventsInputSchema = z
49
+ .object({
50
+ job_id: idSchema,
51
+ execution_id: idSchema,
52
+ limit: z
53
+ .number()
54
+ .int()
55
+ .min(1)
56
+ .max(AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX)
57
+ .default(AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_LIMIT),
58
+ cursor: z.string().min(1).optional(),
59
+ })
60
+ .strict();
61
+
62
+ export const getExecutionTriggerEventInputSchema = z
63
+ .object({
64
+ job_id: idSchema,
65
+ execution_id: idSchema,
66
+ event_ref: eventRefSchema,
67
+ })
68
+ .strict();
69
+
70
+ export type ListExecutionTriggerEventsInputDto = z.output<
71
+ typeof listExecutionTriggerEventsInputSchema
72
+ >;
73
+ export type GetExecutionTriggerEventInputDto = z.output<typeof getExecutionTriggerEventInputSchema>;
74
+
75
+ export const listExecutionTriggerEventsResultSchema = z
76
+ .object({
77
+ job_id: idSchema,
78
+ execution_id: idSchema,
79
+ trigger_events: z
80
+ .array(executionTriggerEventSummarySchema)
81
+ .max(AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX),
82
+ next_cursor: z.string().nullable(),
83
+ total: z.number().int().nonnegative().optional(),
84
+ })
85
+ .strict();
86
+
87
+ export type ListExecutionTriggerEventsResultDto = z.infer<
88
+ typeof listExecutionTriggerEventsResultSchema
89
+ >;
90
+
91
+ export const getExecutionTriggerEventResultSchema = executionTriggerEventSummarySchema
92
+ .extend({
93
+ /** Serialized JSON text. It is untrusted data, not a typed workflow value. */
94
+ payload_preview: payloadPreviewSchema.nullable(),
95
+ payload_preview_truncated: z.literal(true).optional(),
96
+ payload_preview_total_bytes: z.number().int().nonnegative().optional(),
97
+ })
98
+ .strict();
99
+
100
+ export type GetExecutionTriggerEventResultDto = z.infer<
101
+ typeof getExecutionTriggerEventResultSchema
102
+ >;
103
+
104
+ const uuid = {type: 'string', format: 'uuid'} as const;
105
+ const dateTime = {type: 'string', format: 'date-time'} as const;
106
+ const text = {type: 'string', maxLength: AGENT_ACCESS_TEXT_MAX_BYTES} as const;
107
+ const eventRef = {type: 'string', minLength: 1} as const;
108
+ const serializedJson = {
109
+ type: 'string',
110
+ maxLength: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PREVIEW_MAX_BYTES,
111
+ contentMediaType: 'application/json',
112
+ } as const;
113
+ const nullable = (schema: Record<string, unknown>) => ({anyOf: [schema, {type: 'null'}]}) as const;
114
+
115
+ export const listExecutionTriggerEventsInputJsonSchema = {
116
+ type: 'object',
117
+ properties: {
118
+ job_id: uuid,
119
+ execution_id: uuid,
120
+ limit: {
121
+ type: 'integer',
122
+ minimum: 1,
123
+ maximum: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX,
124
+ default: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_LIMIT,
125
+ },
126
+ cursor: {type: 'string', minLength: 1},
127
+ },
128
+ required: ['job_id', 'execution_id'],
129
+ additionalProperties: false,
130
+ } as const satisfies AgentAccessObjectSchema;
131
+
132
+ export const getExecutionTriggerEventInputJsonSchema = {
133
+ type: 'object',
134
+ properties: {job_id: uuid, execution_id: uuid, event_ref: eventRef},
135
+ required: ['job_id', 'execution_id', 'event_ref'],
136
+ additionalProperties: false,
137
+ } as const satisfies AgentAccessObjectSchema;
138
+
139
+ const executionTriggerEventSummaryJson = {
140
+ type: 'object',
141
+ properties: {
142
+ event_ref: eventRef,
143
+ delivery_id: text,
144
+ source: text,
145
+ event: text,
146
+ disposition: {type: 'string', enum: ['fire', 'resolve']},
147
+ outcome: {
148
+ type: 'string',
149
+ enum: ['pending', 'consumed', 'honored', 'rejected', 'abandoned'],
150
+ },
151
+ outcome_reason: {
152
+ anyOf: [
153
+ {
154
+ type: 'string',
155
+ enum: ['payload_too_large', 'until', 'timeout', 'max_executions', 'cancelled'],
156
+ },
157
+ {type: 'null'},
158
+ ],
159
+ },
160
+ received_at: dateTime,
161
+ stored_payload_bytes: {type: 'integer', minimum: 0},
162
+ normalized_event_bytes: {type: 'integer', minimum: 0},
163
+ },
164
+ required: [
165
+ 'event_ref',
166
+ 'delivery_id',
167
+ 'source',
168
+ 'event',
169
+ 'disposition',
170
+ 'outcome',
171
+ 'outcome_reason',
172
+ 'received_at',
173
+ 'stored_payload_bytes',
174
+ 'normalized_event_bytes',
175
+ ],
176
+ additionalProperties: false,
177
+ } as const;
178
+
179
+ const executionTriggerEventDetailJson = {
180
+ ...executionTriggerEventSummaryJson,
181
+ properties: {
182
+ ...executionTriggerEventSummaryJson.properties,
183
+ payload_preview: nullable(serializedJson),
184
+ payload_preview_truncated: {const: true},
185
+ payload_preview_total_bytes: {type: 'integer', minimum: 0},
186
+ },
187
+ required: [...executionTriggerEventSummaryJson.required, 'payload_preview'],
188
+ } as const;
189
+
190
+ export const listExecutionTriggerEventsResultJsonSchema = {
191
+ type: 'object',
192
+ properties: {
193
+ job_id: uuid,
194
+ execution_id: uuid,
195
+ trigger_events: {
196
+ type: 'array',
197
+ maxItems: AGENT_ACCESS_EXECUTION_TRIGGER_EVENT_PAGE_MAX,
198
+ items: executionTriggerEventSummaryJson,
199
+ },
200
+ next_cursor: nullable({type: 'string', minLength: 1}),
201
+ total: {type: 'integer', minimum: 0},
202
+ },
203
+ required: ['job_id', 'execution_id', 'trigger_events', 'next_cursor'],
204
+ additionalProperties: false,
205
+ } as const satisfies AgentAccessObjectSchema;
206
+
207
+ export const getExecutionTriggerEventResultJsonSchema =
208
+ executionTriggerEventDetailJson satisfies AgentAccessObjectSchema;
209
+
210
+ function isSerializedJson(value: string): boolean {
211
+ try {
212
+ JSON.parse(value);
213
+ return true;
214
+ } catch {
215
+ return false;
216
+ }
217
+ }