@shipfox/api-logs-dto 16.0.0 → 20.0.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-logs-dto",
3
3
  "license": "MIT",
4
- "version": "16.0.0",
4
+ "version": "20.0.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
package/src/index.ts CHANGED
@@ -48,3 +48,4 @@ export {
48
48
  sessionViewToolCallRowSchema,
49
49
  sessionViewToolResultRowSchema,
50
50
  } from './schemas/index.js';
51
+ export {DEFAULT_STEP_LOG_TAIL_LINES, MAX_STEP_LOG_TAIL_LINES} from './tail.js';
@@ -1,6 +1,35 @@
1
1
  import {logsInterModuleContract} from './inter-module.js';
2
2
 
3
3
  describe('logsInterModuleContract', () => {
4
+ test('accepts exact-attempt tail reads and defaults the line window', () => {
5
+ const input = logsInterModuleContract.methods.readStepLogTail.input.parse({
6
+ stepId: '00000000-0000-4000-8000-000000000005',
7
+ attempt: 2,
8
+ });
9
+
10
+ expect(input).toEqual({
11
+ stepId: '00000000-0000-4000-8000-000000000005',
12
+ attempt: 2,
13
+ tailLines: 500,
14
+ });
15
+ expect(
16
+ logsInterModuleContract.methods.readStepLogTail.output.parse({
17
+ content: '2026-01-01T00:00:00.000Z stdout: hello',
18
+ totalLines: 12,
19
+ }),
20
+ ).toMatchObject({totalLines: 12});
21
+ expect(logsInterModuleContract.methods.readStepLogTail.output.parse(null)).toBeNull();
22
+ });
23
+
24
+ test('keeps the tail request bounded and exact-attempt', () => {
25
+ const schema = logsInterModuleContract.methods.readStepLogTail;
26
+ const stepId = '00000000-0000-4000-8000-000000000005';
27
+
28
+ expect(schema.input.safeParse({stepId, attempt: 1, tailLines: 0}).success).toBe(false);
29
+ expect(schema.input.safeParse({stepId, attempt: 1, tailLines: 2_001}).success).toBe(false);
30
+ expect(schema.input.safeParse({stepId, attempt: 1, tailLines: 1.5}).success).toBe(false);
31
+ });
32
+
4
33
  test('accepts server-origin append commands', () => {
5
34
  const input = logsInterModuleContract.methods.appendServerRecords.input.parse({
6
35
  jobId: '00000000-0000-4000-8000-000000000001',
@@ -1,22 +1,46 @@
1
1
  import {defineInterModuleContract, type InterModuleClient} from '@shipfox/inter-module';
2
2
  import {z} from 'zod';
3
3
  import {serverLogRecordSchema} from './schemas/index.js';
4
+ import {DEFAULT_STEP_LOG_TAIL_LINES, MAX_STEP_LOG_TAIL_LINES} from './tail.js';
4
5
 
5
6
  const idSchema = z.string().uuid();
6
7
 
8
+ export {DEFAULT_STEP_LOG_TAIL_LINES, MAX_STEP_LOG_TAIL_LINES} from './tail.js';
9
+
7
10
  /**
8
- * Producer-owned Logs commands used by synchronous callers. The only method
9
- * today is the server-origin append for server-executed steps (the tool step
10
- * executor): it writes already-normalized stored records through the same
11
- * offset-CAS and budget pipeline as the lease-bound runner route, but with
12
- * chunk `origin` `server` and a tail-derived CAS offset (the caller owns no
13
- * spool cursor). This is a trusted internal boundary, not an authorization
14
- * boundary: the caller must derive the identity fields from its execution
15
- * context rather than pass through arbitrary external input.
11
+ * Producer-owned Logs commands used by synchronous callers. The exact-attempt tail read and
12
+ * server-origin append for server-executed steps (the tool step executor) run inside this
13
+ * boundary. The append writes already-normalized stored records through the same offset-CAS and
14
+ * budget pipeline as the lease-bound runner route, but with chunk `origin` `server` and a
15
+ * tail-derived CAS offset (the caller owns no spool cursor). This is a trusted internal
16
+ * boundary, not an authorization boundary: callers must derive identity fields from their
17
+ * execution context rather than pass through arbitrary external input.
16
18
  */
17
19
  export const logsInterModuleContract = defineInterModuleContract({
18
20
  module: 'logs',
19
21
  methods: {
22
+ /** Reads one exact step attempt as bounded rendered text. */
23
+ readStepLogTail: {
24
+ input: z.object({
25
+ stepId: idSchema,
26
+ attempt: z.number().int().min(1).max(2_147_483_647),
27
+ tailLines: z
28
+ .number()
29
+ .int()
30
+ .min(1)
31
+ .max(MAX_STEP_LOG_TAIL_LINES)
32
+ .default(DEFAULT_STEP_LOG_TAIL_LINES),
33
+ }),
34
+ output: z
35
+ .object({
36
+ content: z.string(),
37
+ totalLines: z.number().int().nonnegative().optional(),
38
+ })
39
+ .nullable(),
40
+ errors: {
41
+ 'compacted-log-unavailable': z.object({}),
42
+ },
43
+ },
20
44
  appendServerRecords: {
21
45
  input: z.object({
22
46
  jobId: idSchema,
package/src/tail.ts ADDED
@@ -0,0 +1,3 @@
1
+ /** Default and maximum line windows accepted by the bounded step-log tail operation. */
2
+ export const DEFAULT_STEP_LOG_TAIL_LINES = 500;
3
+ export const MAX_STEP_LOG_TAIL_LINES = 2_000;