@shipfox/client-logs 3.0.1 → 5.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/components/agent-session-rows.d.ts +1 -1
- package/dist/components/agent-session-rows.d.ts.map +1 -1
- package/dist/components/agent-session-rows.js.map +1 -1
- package/dist/components/log-view.d.ts +1 -1
- package/dist/components/log-view.d.ts.map +1 -1
- package/dist/components/log-view.js.map +1 -1
- package/dist/components/system-markers.js +2 -2
- package/dist/components/system-markers.js.map +1 -1
- package/dist/core/log-model.d.ts +93 -0
- package/dist/core/log-model.d.ts.map +1 -0
- package/dist/core/log-model.js +3 -0
- package/dist/core/log-model.js.map +1 -0
- package/dist/core/log-read.d.ts +7 -14
- package/dist/core/log-read.d.ts.map +1 -1
- package/dist/core/log-read.js +9 -13
- package/dist/core/log-read.js.map +1 -1
- package/dist/core/log-tree.d.ts +1 -1
- package/dist/core/log-tree.d.ts.map +1 -1
- package/dist/core/log-tree.js +3 -3
- package/dist/core/log-tree.js.map +1 -1
- package/dist/hooks/api/log-mapper.d.ts +10 -0
- package/dist/hooks/api/log-mapper.d.ts.map +1 -0
- package/dist/hooks/api/log-mapper.js +92 -0
- package/dist/hooks/api/log-mapper.js.map +1 -0
- package/dist/hooks/api/step-logs.d.ts +7 -2
- package/dist/hooks/api/step-logs.d.ts.map +1 -1
- package/dist/hooks/api/step-logs.js +14 -5
- package/dist/hooks/api/step-logs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +2 -31
- package/src/components/agent-session-rows.tsx +1 -1
- package/src/components/log-group.stories.tsx +2 -2
- package/src/components/log-view.stories.tsx +10 -10
- package/src/components/log-view.test.tsx +3 -3
- package/src/components/log-view.tsx +1 -1
- package/src/components/system-markers.stories.tsx +3 -3
- package/src/components/system-markers.tsx +2 -2
- package/src/core/log-model.ts +76 -0
- package/src/core/log-read.test.ts +58 -139
- package/src/core/log-read.ts +12 -25
- package/src/core/log-tree.test.ts +10 -10
- package/src/core/log-tree.ts +4 -4
- package/src/hooks/api/log-mapper.test.ts +56 -0
- package/src/hooks/api/log-mapper.ts +75 -0
- package/src/hooks/api/step-logs.test.ts +21 -1
- package/src/hooks/api/step-logs.ts +24 -7
- package/src/index.ts +7 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/log-tree.ts"],"sourcesContent":["import type {LogRecord} from '@shipfox/api-logs-dto';\n\n/**\n * Pure render transform for the step-log read stream. The runner emits a flat,\n * ordered NDJSON record list; `group_start`/`group_end` form a tree that the\n * reader reconstructs here before rendering. No React, no state — one function\n * over the record array.\n *\n * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }\n *\n * Group closing matches `group_id` (not a blind top-of-stack pop) so a stream that\n * drops a `group_start` under backlog/gap pressure but still delivers its\n * `group_end` does not mis-nest everything after it.\n */\n\nexport type OutputLogRecord = Extract<LogRecord, {type: 'output'}>;\nexport type GroupStartLogRecord = Extract<LogRecord, {type: 'group_start'}>;\nexport type EndLogRecord = Extract<LogRecord, {type: 'end'}>;\nexport type GapLogRecord = Extract<LogRecord, {type: 'gap'}>;\nexport type CappedLogRecord = Extract<LogRecord, {type: 'capped'}>;\nexport type RunnerLostLogRecord = Extract<LogRecord, {type: 'runner_lost'}>;\nexport type AgentSessionLogRecord = Extract<LogRecord, {type: 'agent_session'}>;\nexport type MarkerLogRecord = EndLogRecord | GapLogRecord | CappedLogRecord | RunnerLostLogRecord;\n\n/**\n * Stable, unique render key in creation order. A natural key is not enough: `group_id`\n * and a marker's `(type, ts)` can both repeat among siblings once a consumer feeds a\n * concatenated multi-step/retry stream (or two markers land in the same millisecond),\n * and the append-only build order keeps `seq` stable across re-renders.\n */\nexport interface LogNodeBase {\n seq: number;\n}\n\nexport interface OutputLogNode extends LogNodeBase {\n kind: 'output';\n lineNumber: number;\n record: OutputLogRecord;\n}\n\nexport interface MarkerLogNode extends LogNodeBase {\n kind: 'marker';\n record: MarkerLogRecord;\n}\n\nexport interface GroupLogNode extends LogNodeBase {\n kind: 'group';\n record: GroupStartLogRecord;\n /** False when no matching `group_end` arrived (still streaming, or truncated). */\n closed: boolean;\n /** `group_end` timestamp when closed by its matching end, else null. */\n endTs: number | null;\n /** Precomputed: subtree contains a `runner_lost` (a genuine failure). `stderr` is a channel, not an error, so it never sets this. */\n hasError: boolean;\n /** Precomputed output-line count in the subtree, for the collapsed summary. */\n lineCount: number;\n children: LogNode[];\n}\n\nexport interface SessionLogNode extends LogNodeBase {\n kind: 'session';\n record: AgentSessionLogRecord;\n}\n\nexport type LogNode = OutputLogNode | MarkerLogNode | GroupLogNode | SessionLogNode;\n\nexport interface LogTree {\n nodes: LogNode[];\n /** The stream is closed: the records contain an `end` or a `runner_lost`. */\n terminated: boolean;\n /** First record's timestamp; the baseline for relative timestamps. Null when empty. */\n originTs: number | null;\n /** Physical output lines (one per `output` record in v1); drives the end banner. */\n lineCount: number;\n}\n\nconst TRAILING_NEWLINE = /\\r?\\n$/;\n\n/** Strips a single trailing line ending (CRLF or LF) so a line-framed record renders without a blank continuation. */\nexport function stripTrailingNewline(data: string): string {\n return data.replace(TRAILING_NEWLINE, '');\n}\n\nexport function assertNever(value: never): never {\n throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);\n}\n\nexport function buildLogTree(records: readonly LogRecord[]): LogTree {\n const nodes: LogNode[] = [];\n const stack: GroupLogNode[] = [];\n let seq = 0;\n let lineNumber = 0;\n let lineCount = 0;\n let terminated = false;\n let originTs: number | null = null;\n\n const childrenOf = (): LogNode[] => stack[stack.length - 1]?.children ?? nodes;\n\n // Bubble a failure signal (a runner_lost only) to every currently-open ancestor group\n // in one pass, so `hasError` is read in O(1) at render time instead of re-walking subtrees.\n const markOpenGroupsError = (): void => {\n for (const frame of stack) frame.hasError = true;\n };\n\n for (const record of records) {\n if (originTs === null) originTs = record.ts;\n switch (record.type) {\n case 'output': {\n lineNumber += 1;\n lineCount += 1;\n for (const frame of stack) frame.lineCount += 1;\n childrenOf().push({kind: 'output', seq: seq++, lineNumber, record});\n break;\n }\n case 'group_start': {\n // Reconcile the open stack to the declared parent before nesting. `parent_group_id`\n // is the runner's stack top at emit time (null at the root), so any reader frame\n // below that parent (or every open frame, when the parent is root) is a group whose\n // own `group_end` was dropped under backlog pressure. Orphan-close those frames so a\n // dropped end never mis-parents the groups that follow. A parent whose own start was\n // dropped is not on the stack: it falls through to best-effort root placement.\n const parentId = record.parent_group_id;\n let parentIndex = -1;\n if (parentId !== null) {\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.group_id === parentId) {\n parentIndex = i;\n break;\n }\n }\n }\n for (let i = stack.length - 1; i > parentIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n stack.length = parentIndex + 1;\n\n const group: GroupLogNode = {\n kind: 'group',\n seq: seq++,\n record,\n closed: false,\n endTs: null,\n hasError: false,\n lineCount: 0,\n children: [],\n };\n childrenOf().push(group);\n stack.push(group);\n break;\n }\n case 'group_end': {\n // Close the matching open group_id; any inner frames orphaned by a dropped\n // group_end close with it. An end with no matching open start is ignored.\n let matchIndex = -1;\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.group_id === record.group_id) {\n matchIndex = i;\n break;\n }\n }\n if (matchIndex !== -1) {\n for (let i = stack.length - 1; i >= matchIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n const matched = stack[matchIndex];\n if (matched) matched.endTs = record.ts;\n stack.length = matchIndex;\n }\n break;\n }\n case 'end':\n case 'gap':\n case 'capped': {\n if (record.type === 'end') terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n break;\n }\n case 'runner_lost': {\n terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n markOpenGroupsError();\n break;\n }\n case 'agent_session':\n childrenOf().push({kind: 'session', seq: seq++, record});\n break;\n default:\n assertNever(record);\n }\n }\n\n return {\n nodes,\n terminated,\n originTs,\n lineCount,\n };\n}\n"],"names":["TRAILING_NEWLINE","stripTrailingNewline","data","replace","assertNever","value","Error","JSON","stringify","buildLogTree","records","nodes","stack","seq","lineNumber","lineCount","terminated","originTs","childrenOf","length","children","markOpenGroupsError","frame","hasError","record","ts","type","push","kind","parentId","parent_group_id","parentIndex","i","group_id","closed","group","endTs","matchIndex","matched"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/log-tree.ts"],"sourcesContent":["import type {LogRecord} from './log-model.js';\n\n/**\n * Pure render transform for the step-log read stream. The runner emits a flat,\n * ordered NDJSON record list; `group_start`/`group_end` form a tree that the\n * reader reconstructs here before rendering. No React, no state — one function\n * over the record array.\n *\n * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }\n *\n * Group closing matches `group_id` (not a blind top-of-stack pop) so a stream that\n * drops a `group_start` under backlog/gap pressure but still delivers its\n * `group_end` does not mis-nest everything after it.\n */\n\nexport type OutputLogRecord = Extract<LogRecord, {type: 'output'}>;\nexport type GroupStartLogRecord = Extract<LogRecord, {type: 'group_start'}>;\nexport type EndLogRecord = Extract<LogRecord, {type: 'end'}>;\nexport type GapLogRecord = Extract<LogRecord, {type: 'gap'}>;\nexport type CappedLogRecord = Extract<LogRecord, {type: 'capped'}>;\nexport type RunnerLostLogRecord = Extract<LogRecord, {type: 'runner_lost'}>;\nexport type AgentSessionLogRecord = Extract<LogRecord, {type: 'agent_session'}>;\nexport type MarkerLogRecord = EndLogRecord | GapLogRecord | CappedLogRecord | RunnerLostLogRecord;\n\n/**\n * Stable, unique render key in creation order. A natural key is not enough: `group_id`\n * and a marker's `(type, ts)` can both repeat among siblings once a consumer feeds a\n * concatenated multi-step/retry stream (or two markers land in the same millisecond),\n * and the append-only build order keeps `seq` stable across re-renders.\n */\nexport interface LogNodeBase {\n seq: number;\n}\n\nexport interface OutputLogNode extends LogNodeBase {\n kind: 'output';\n lineNumber: number;\n record: OutputLogRecord;\n}\n\nexport interface MarkerLogNode extends LogNodeBase {\n kind: 'marker';\n record: MarkerLogRecord;\n}\n\nexport interface GroupLogNode extends LogNodeBase {\n kind: 'group';\n record: GroupStartLogRecord;\n /** False when no matching `group_end` arrived (still streaming, or truncated). */\n closed: boolean;\n /** `group_end` timestamp when closed by its matching end, else null. */\n endTs: number | null;\n /** Precomputed: subtree contains a `runner_lost` (a genuine failure). `stderr` is a channel, not an error, so it never sets this. */\n hasError: boolean;\n /** Precomputed output-line count in the subtree, for the collapsed summary. */\n lineCount: number;\n children: LogNode[];\n}\n\nexport interface SessionLogNode extends LogNodeBase {\n kind: 'session';\n record: AgentSessionLogRecord;\n}\n\nexport type LogNode = OutputLogNode | MarkerLogNode | GroupLogNode | SessionLogNode;\n\nexport interface LogTree {\n nodes: LogNode[];\n /** The stream is closed: the records contain an `end` or a `runner_lost`. */\n terminated: boolean;\n /** First record's timestamp; the baseline for relative timestamps. Null when empty. */\n originTs: number | null;\n /** Physical output lines (one per `output` record in v1); drives the end banner. */\n lineCount: number;\n}\n\nconst TRAILING_NEWLINE = /\\r?\\n$/;\n\n/** Strips a single trailing line ending (CRLF or LF) so a line-framed record renders without a blank continuation. */\nexport function stripTrailingNewline(data: string): string {\n return data.replace(TRAILING_NEWLINE, '');\n}\n\nexport function assertNever(value: never): never {\n throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);\n}\n\nexport function buildLogTree(records: readonly LogRecord[]): LogTree {\n const nodes: LogNode[] = [];\n const stack: GroupLogNode[] = [];\n let seq = 0;\n let lineNumber = 0;\n let lineCount = 0;\n let terminated = false;\n let originTs: number | null = null;\n\n const childrenOf = (): LogNode[] => stack[stack.length - 1]?.children ?? nodes;\n\n // Bubble a failure signal (a runner_lost only) to every currently-open ancestor group\n // in one pass, so `hasError` is read in O(1) at render time instead of re-walking subtrees.\n const markOpenGroupsError = (): void => {\n for (const frame of stack) frame.hasError = true;\n };\n\n for (const record of records) {\n if (originTs === null) originTs = record.ts;\n switch (record.type) {\n case 'output': {\n lineNumber += 1;\n lineCount += 1;\n for (const frame of stack) frame.lineCount += 1;\n childrenOf().push({kind: 'output', seq: seq++, lineNumber, record});\n break;\n }\n case 'group_start': {\n // Reconcile the open stack to the declared parent before nesting. `parent_group_id`\n // is the runner's stack top at emit time (null at the root), so any reader frame\n // below that parent (or every open frame, when the parent is root) is a group whose\n // own `group_end` was dropped under backlog pressure. Orphan-close those frames so a\n // dropped end never mis-parents the groups that follow. A parent whose own start was\n // dropped is not on the stack: it falls through to best-effort root placement.\n const parentId = record.parentGroupId;\n let parentIndex = -1;\n if (parentId !== null) {\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === parentId) {\n parentIndex = i;\n break;\n }\n }\n }\n for (let i = stack.length - 1; i > parentIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n stack.length = parentIndex + 1;\n\n const group: GroupLogNode = {\n kind: 'group',\n seq: seq++,\n record,\n closed: false,\n endTs: null,\n hasError: false,\n lineCount: 0,\n children: [],\n };\n childrenOf().push(group);\n stack.push(group);\n break;\n }\n case 'group_end': {\n // Close the matching open group_id; any inner frames orphaned by a dropped\n // group_end close with it. An end with no matching open start is ignored.\n let matchIndex = -1;\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === record.groupId) {\n matchIndex = i;\n break;\n }\n }\n if (matchIndex !== -1) {\n for (let i = stack.length - 1; i >= matchIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n const matched = stack[matchIndex];\n if (matched) matched.endTs = record.ts;\n stack.length = matchIndex;\n }\n break;\n }\n case 'end':\n case 'gap':\n case 'capped': {\n if (record.type === 'end') terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n break;\n }\n case 'runner_lost': {\n terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n markOpenGroupsError();\n break;\n }\n case 'agent_session':\n childrenOf().push({kind: 'session', seq: seq++, record});\n break;\n default:\n assertNever(record);\n }\n }\n\n return {\n nodes,\n terminated,\n originTs,\n lineCount,\n };\n}\n"],"names":["TRAILING_NEWLINE","stripTrailingNewline","data","replace","assertNever","value","Error","JSON","stringify","buildLogTree","records","nodes","stack","seq","lineNumber","lineCount","terminated","originTs","childrenOf","length","children","markOpenGroupsError","frame","hasError","record","ts","type","push","kind","parentId","parentGroupId","parentIndex","i","groupId","closed","group","endTs","matchIndex","matched"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type LogRecord as LogRecordDto, type ReadLogsResponseDto } from '@shipfox/api-logs-dto';
|
|
2
|
+
import type { InlineLogRead, LogRecord, PresignedLogRead } from '#core/log-model.js';
|
|
3
|
+
export declare function toLogRead(response: ReadLogsResponseDto): InlineLogRead | PresignedLogRead;
|
|
4
|
+
/**
|
|
5
|
+
* The compacted object is fetched from a presigned external URL, so every line is
|
|
6
|
+
* validated at this boundary before it can enter the package-owned query snapshot.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseLogNdjson(ndjson: string): LogRecord[];
|
|
9
|
+
export declare function toLogRecord(record: LogRecordDto): LogRecord;
|
|
10
|
+
//# sourceMappingURL=log-mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/log-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,IAAI,YAAY,EAE9B,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAC,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAiB,MAAM,oBAAoB,CAAC;AAInG,wBAAgB,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,aAAa,GAAG,gBAAgB,CAmBzF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAK1D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAyB3D"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { parseLogRecordLine } from '@shipfox/api-logs-dto';
|
|
2
|
+
const NDJSON_LINE_BREAK = /\r?\n/;
|
|
3
|
+
export function toLogRead(response) {
|
|
4
|
+
if (response.mode === 'presigned') {
|
|
5
|
+
return {
|
|
6
|
+
mode: 'presigned',
|
|
7
|
+
url: response.url,
|
|
8
|
+
expiresAt: response.expires_at,
|
|
9
|
+
totalBytes: response.total_bytes,
|
|
10
|
+
truncated: response.truncated
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
mode: 'inline',
|
|
15
|
+
ndjson: response.ndjson,
|
|
16
|
+
nextCursor: response.next_cursor,
|
|
17
|
+
hasMore: response.has_more,
|
|
18
|
+
state: response.state,
|
|
19
|
+
truncated: response.truncated
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The compacted object is fetched from a presigned external URL, so every line is
|
|
24
|
+
* validated at this boundary before it can enter the package-owned query snapshot.
|
|
25
|
+
*/ export function parseLogNdjson(ndjson) {
|
|
26
|
+
return ndjson.split(NDJSON_LINE_BREAK).filter((line)=>line.length > 0).map((line)=>toLogRecord(parseLogRecordLine(line)));
|
|
27
|
+
}
|
|
28
|
+
export function toLogRecord(record) {
|
|
29
|
+
const base = {
|
|
30
|
+
v: record.v,
|
|
31
|
+
ts: record.ts
|
|
32
|
+
};
|
|
33
|
+
switch(record.type){
|
|
34
|
+
case 'output':
|
|
35
|
+
return {
|
|
36
|
+
...base,
|
|
37
|
+
type: record.type,
|
|
38
|
+
stream: record.stream,
|
|
39
|
+
data: record.data
|
|
40
|
+
};
|
|
41
|
+
case 'group_start':
|
|
42
|
+
return {
|
|
43
|
+
...base,
|
|
44
|
+
type: record.type,
|
|
45
|
+
groupId: record.group_id,
|
|
46
|
+
parentGroupId: record.parent_group_id,
|
|
47
|
+
name: record.name
|
|
48
|
+
};
|
|
49
|
+
case 'group_end':
|
|
50
|
+
return {
|
|
51
|
+
...base,
|
|
52
|
+
type: record.type,
|
|
53
|
+
groupId: record.group_id
|
|
54
|
+
};
|
|
55
|
+
case 'end':
|
|
56
|
+
return {
|
|
57
|
+
...base,
|
|
58
|
+
type: record.type,
|
|
59
|
+
totalBytes: record.total_bytes
|
|
60
|
+
};
|
|
61
|
+
case 'gap':
|
|
62
|
+
return {
|
|
63
|
+
...base,
|
|
64
|
+
type: record.type,
|
|
65
|
+
droppedBytes: record.dropped_bytes
|
|
66
|
+
};
|
|
67
|
+
case 'agent_session':
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
type: record.type,
|
|
71
|
+
row: toSessionViewRow(record.row)
|
|
72
|
+
};
|
|
73
|
+
case 'capped':
|
|
74
|
+
case 'runner_lost':
|
|
75
|
+
return {
|
|
76
|
+
...base,
|
|
77
|
+
type: record.type
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function toSessionViewRow(row) {
|
|
82
|
+
return row.kind === 'message' || row.kind === 'lifecycle' ? {
|
|
83
|
+
...row,
|
|
84
|
+
meta: row.meta.map((meta)=>({
|
|
85
|
+
...meta
|
|
86
|
+
}))
|
|
87
|
+
} : {
|
|
88
|
+
...row
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=log-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/log-mapper.ts"],"sourcesContent":["import {\n type LogRecord as LogRecordDto,\n parseLogRecordLine,\n type ReadLogsResponseDto,\n} from '@shipfox/api-logs-dto';\nimport type {InlineLogRead, LogRecord, PresignedLogRead, SessionViewRow} from '#core/log-model.js';\n\nconst NDJSON_LINE_BREAK = /\\r?\\n/;\n\nexport function toLogRead(response: ReadLogsResponseDto): InlineLogRead | PresignedLogRead {\n if (response.mode === 'presigned') {\n return {\n mode: 'presigned',\n url: response.url,\n expiresAt: response.expires_at,\n totalBytes: response.total_bytes,\n truncated: response.truncated,\n };\n }\n\n return {\n mode: 'inline',\n ndjson: response.ndjson,\n nextCursor: response.next_cursor,\n hasMore: response.has_more,\n state: response.state,\n truncated: response.truncated,\n };\n}\n\n/**\n * The compacted object is fetched from a presigned external URL, so every line is\n * validated at this boundary before it can enter the package-owned query snapshot.\n */\nexport function parseLogNdjson(ndjson: string): LogRecord[] {\n return ndjson\n .split(NDJSON_LINE_BREAK)\n .filter((line) => line.length > 0)\n .map((line) => toLogRecord(parseLogRecordLine(line)));\n}\n\nexport function toLogRecord(record: LogRecordDto): LogRecord {\n const base: {v: 1; ts: number} = {v: record.v, ts: record.ts};\n switch (record.type) {\n case 'output':\n return {...base, type: record.type, stream: record.stream, data: record.data};\n case 'group_start':\n return {\n ...base,\n type: record.type,\n groupId: record.group_id,\n parentGroupId: record.parent_group_id,\n name: record.name,\n };\n case 'group_end':\n return {...base, type: record.type, groupId: record.group_id};\n case 'end':\n return {...base, type: record.type, totalBytes: record.total_bytes};\n case 'gap':\n return {...base, type: record.type, droppedBytes: record.dropped_bytes};\n case 'agent_session':\n return {...base, type: record.type, row: toSessionViewRow(record.row)};\n case 'capped':\n case 'runner_lost':\n return {...base, type: record.type};\n }\n}\n\nfunction toSessionViewRow(\n row: Extract<LogRecordDto, {type: 'agent_session'}>['row'],\n): SessionViewRow {\n return row.kind === 'message' || row.kind === 'lifecycle'\n ? {...row, meta: row.meta.map((meta) => ({...meta}))}\n : {...row};\n}\n"],"names":["parseLogRecordLine","NDJSON_LINE_BREAK","toLogRead","response","mode","url","expiresAt","expires_at","totalBytes","total_bytes","truncated","ndjson","nextCursor","next_cursor","hasMore","has_more","state","parseLogNdjson","split","filter","line","length","map","toLogRecord","record","base","v","ts","type","stream","data","groupId","group_id","parentGroupId","parent_group_id","name","droppedBytes","dropped_bytes","row","toSessionViewRow","kind","meta"],"mappings":"AAAA,SAEEA,kBAAkB,QAEb,wBAAwB;AAG/B,MAAMC,oBAAoB;AAE1B,OAAO,SAASC,UAAUC,QAA6B;IACrD,IAAIA,SAASC,IAAI,KAAK,aAAa;QACjC,OAAO;YACLA,MAAM;YACNC,KAAKF,SAASE,GAAG;YACjBC,WAAWH,SAASI,UAAU;YAC9BC,YAAYL,SAASM,WAAW;YAChCC,WAAWP,SAASO,SAAS;QAC/B;IACF;IAEA,OAAO;QACLN,MAAM;QACNO,QAAQR,SAASQ,MAAM;QACvBC,YAAYT,SAASU,WAAW;QAChCC,SAASX,SAASY,QAAQ;QAC1BC,OAAOb,SAASa,KAAK;QACrBN,WAAWP,SAASO,SAAS;IAC/B;AACF;AAEA;;;CAGC,GACD,OAAO,SAASO,eAAeN,MAAc;IAC3C,OAAOA,OACJO,KAAK,CAACjB,mBACNkB,MAAM,CAAC,CAACC,OAASA,KAAKC,MAAM,GAAG,GAC/BC,GAAG,CAAC,CAACF,OAASG,YAAYvB,mBAAmBoB;AAClD;AAEA,OAAO,SAASG,YAAYC,MAAoB;IAC9C,MAAMC,OAA2B;QAACC,GAAGF,OAAOE,CAAC;QAAEC,IAAIH,OAAOG,EAAE;IAAA;IAC5D,OAAQH,OAAOI,IAAI;QACjB,KAAK;YACH,OAAO;gBAAC,GAAGH,IAAI;gBAAEG,MAAMJ,OAAOI,IAAI;gBAAEC,QAAQL,OAAOK,MAAM;gBAAEC,MAAMN,OAAOM,IAAI;YAAA;QAC9E,KAAK;YACH,OAAO;gBACL,GAAGL,IAAI;gBACPG,MAAMJ,OAAOI,IAAI;gBACjBG,SAASP,OAAOQ,QAAQ;gBACxBC,eAAeT,OAAOU,eAAe;gBACrCC,MAAMX,OAAOW,IAAI;YACnB;QACF,KAAK;YACH,OAAO;gBAAC,GAAGV,IAAI;gBAAEG,MAAMJ,OAAOI,IAAI;gBAAEG,SAASP,OAAOQ,QAAQ;YAAA;QAC9D,KAAK;YACH,OAAO;gBAAC,GAAGP,IAAI;gBAAEG,MAAMJ,OAAOI,IAAI;gBAAEpB,YAAYgB,OAAOf,WAAW;YAAA;QACpE,KAAK;YACH,OAAO;gBAAC,GAAGgB,IAAI;gBAAEG,MAAMJ,OAAOI,IAAI;gBAAEQ,cAAcZ,OAAOa,aAAa;YAAA;QACxE,KAAK;YACH,OAAO;gBAAC,GAAGZ,IAAI;gBAAEG,MAAMJ,OAAOI,IAAI;gBAAEU,KAAKC,iBAAiBf,OAAOc,GAAG;YAAC;QACvE,KAAK;QACL,KAAK;YACH,OAAO;gBAAC,GAAGb,IAAI;gBAAEG,MAAMJ,OAAOI,IAAI;YAAA;IACtC;AACF;AAEA,SAASW,iBACPD,GAA0D;IAE1D,OAAOA,IAAIE,IAAI,KAAK,aAAaF,IAAIE,IAAI,KAAK,cAC1C;QAAC,GAAGF,GAAG;QAAEG,MAAMH,IAAIG,IAAI,CAACnB,GAAG,CAAC,CAACmB,OAAU,CAAA;gBAAC,GAAGA,IAAI;YAAA,CAAA;IAAG,IAClD;QAAC,GAAGH,GAAG;IAAA;AACb"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ReadLogsResponseDto } from '@shipfox/api-logs-dto';
|
|
2
1
|
import { type StepLogSnapshot } from '#core/log-read.js';
|
|
3
2
|
export declare const stepLogsQueryKeys: {
|
|
4
3
|
all: readonly ["step-logs"];
|
|
@@ -10,7 +9,7 @@ interface ReadStepAttemptLogsPageParams {
|
|
|
10
9
|
cursor: number;
|
|
11
10
|
signal?: AbortSignal;
|
|
12
11
|
}
|
|
13
|
-
export declare function readStepAttemptLogsPage({ stepId, attempt, cursor, signal, }: ReadStepAttemptLogsPageParams): Promise<
|
|
12
|
+
export declare function readStepAttemptLogsPage({ stepId, attempt, cursor, signal, }: ReadStepAttemptLogsPageParams): Promise<import("../../core/log-model.js").InlineLogRead | import("../../core/log-model.js").PresignedLogRead>;
|
|
14
13
|
export declare function isMissingStepLogStreamError(error: unknown): boolean;
|
|
15
14
|
export interface UseStepAttemptLogsQueryOptions {
|
|
16
15
|
retryMissingStream?: boolean;
|
|
@@ -19,6 +18,12 @@ export interface UseStepAttemptLogsQueryOptions {
|
|
|
19
18
|
initialErrorRetryCount?: number;
|
|
20
19
|
initialErrorRetryDelayMs?: number;
|
|
21
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Narrow React Query wrapper for step logs. Its query function can read the prior
|
|
23
|
+
* snapshot imperatively, but bounded missing-stream retries need a ref that resets
|
|
24
|
+
* when the step, attempt, or retry budget changes. Keep that lifecycle state here
|
|
25
|
+
* rather than exporting query options that could accidentally share it between views.
|
|
26
|
+
*/
|
|
22
27
|
export declare function useStepAttemptLogsQuery(stepId: string | undefined, attempt: number | undefined, options?: UseStepAttemptLogsQueryOptions): import("@tanstack/react-query").UseQueryResult<NoInfer<StepLogSnapshot>, Error>;
|
|
23
28
|
export {};
|
|
24
29
|
//# sourceMappingURL=step-logs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-logs.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/step-logs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"step-logs.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/step-logs.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,mBAAmB,CAAC;AAG3B,eAAO,MAAM,iBAAiB;;qBAEX,MAAM,WAAW,MAAM;CAEzC,CAAC;AAEF,UAAU,6BAA6B;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,uBAAuB,CAAC,EAC5C,MAAM,EACN,OAAO,EACP,MAAM,EACN,MAAM,GACP,EAAE,6BAA6B,iHAQ/B;AAkBD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEnE;AAED,MAAM,WAAW,8BAA8B;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,yBAAyB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,8BAAmC,mFA2F7C"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readLogsResponseSchema } from '@shipfox/api-logs-dto';
|
|
2
|
+
import { ApiError, checkedApiRequest } from '@shipfox/client-api';
|
|
2
3
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
3
4
|
import { useRef } from 'react';
|
|
4
5
|
import { mergeLogRead, STEP_LOG_LIVE_REFETCH_MS, stepLogRefetchInterval } from '#core/log-read.js';
|
|
6
|
+
import { parseLogNdjson, toLogRead } from './log-mapper.js';
|
|
5
7
|
export const stepLogsQueryKeys = {
|
|
6
8
|
all: [
|
|
7
9
|
'step-logs'
|
|
@@ -17,9 +19,10 @@ export async function readStepAttemptLogsPage({ stepId, attempt, cursor, signal
|
|
|
17
19
|
const params = new URLSearchParams({
|
|
18
20
|
cursor: String(cursor)
|
|
19
21
|
});
|
|
20
|
-
|
|
22
|
+
const response = await checkedApiRequest(readLogsResponseSchema, `/steps/${encodeURIComponent(stepId)}/attempts/${attempt}/logs?${params.toString()}`, {
|
|
21
23
|
signal
|
|
22
24
|
});
|
|
25
|
+
return toLogRead(response);
|
|
23
26
|
}
|
|
24
27
|
let StepLogObjectFetchError = class StepLogObjectFetchError extends Error {
|
|
25
28
|
constructor(status){
|
|
@@ -38,7 +41,12 @@ async function readPresignedLogObject(url, signal) {
|
|
|
38
41
|
export function isMissingStepLogStreamError(error) {
|
|
39
42
|
return error instanceof ApiError && error.status === 404 && error.code === 'not-found';
|
|
40
43
|
}
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Narrow React Query wrapper for step logs. Its query function can read the prior
|
|
46
|
+
* snapshot imperatively, but bounded missing-stream retries need a ref that resets
|
|
47
|
+
* when the step, attempt, or retry budget changes. Keep that lifecycle state here
|
|
48
|
+
* rather than exporting query options that could accidentally share it between views.
|
|
49
|
+
*/ export function useStepAttemptLogsQuery(stepId, attempt, options = {}) {
|
|
42
50
|
const queryClient = useQueryClient();
|
|
43
51
|
const missingStreamFailureCountRef = useRef(0);
|
|
44
52
|
const missingStreamScopeRef = useRef(null);
|
|
@@ -85,12 +93,13 @@ export function useStepAttemptLogsQuery(stepId, attempt, options = {}) {
|
|
|
85
93
|
return mergeLogRead(previous, {
|
|
86
94
|
mode: 'presigned',
|
|
87
95
|
response,
|
|
88
|
-
ndjson
|
|
96
|
+
records: parseLogNdjson(ndjson)
|
|
89
97
|
});
|
|
90
98
|
}
|
|
91
99
|
return mergeLogRead(previous, {
|
|
92
100
|
mode: 'inline',
|
|
93
|
-
response
|
|
101
|
+
response,
|
|
102
|
+
records: parseLogNdjson(response.ndjson)
|
|
94
103
|
});
|
|
95
104
|
},
|
|
96
105
|
retry: (failureCount, error)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/step-logs.ts"],"sourcesContent":["import type {ReadLogsResponseDto} from '@shipfox/api-logs-dto';\nimport {ApiError, apiRequest} from '@shipfox/client-api';\nimport {useQuery, useQueryClient} from '@tanstack/react-query';\nimport {useRef} from 'react';\nimport {\n mergeLogRead,\n STEP_LOG_LIVE_REFETCH_MS,\n type StepLogSnapshot,\n stepLogRefetchInterval,\n} from '#core/log-read.js';\n\nexport const stepLogsQueryKeys = {\n all: ['step-logs'] as const,\n detail: (stepId: string, attempt: number) =>\n [...stepLogsQueryKeys.all, 'detail', stepId, attempt] as const,\n};\n\ninterface ReadStepAttemptLogsPageParams {\n stepId: string;\n attempt: number;\n cursor: number;\n signal?: AbortSignal;\n}\n\nexport async function readStepAttemptLogsPage({\n stepId,\n attempt,\n cursor,\n signal,\n}: ReadStepAttemptLogsPageParams): Promise<ReadLogsResponseDto> {\n const params = new URLSearchParams({cursor: String(cursor)});\n return await apiRequest<ReadLogsResponseDto>(\n `/steps/${encodeURIComponent(stepId)}/attempts/${attempt}/logs?${params.toString()}`,\n {signal},\n );\n}\n\nclass StepLogObjectFetchError extends Error {\n readonly status: number;\n\n constructor(status: number) {\n super(`Could not load compacted logs (${status})`);\n this.name = 'StepLogObjectFetchError';\n this.status = status;\n }\n}\n\nasync function readPresignedLogObject(url: string, signal?: AbortSignal): Promise<string> {\n const response = await fetch(url, signal ? {signal} : undefined);\n if (!response.ok) throw new StepLogObjectFetchError(response.status);\n return await response.text();\n}\n\nexport function isMissingStepLogStreamError(error: unknown): boolean {\n return error instanceof ApiError && error.status === 404 && error.code === 'not-found';\n}\n\nexport interface UseStepAttemptLogsQueryOptions {\n retryMissingStream?: boolean;\n missingStreamRetryCount?: number | undefined;\n missingStreamRetryDelayMs?: number | undefined;\n initialErrorRetryCount?: number;\n initialErrorRetryDelayMs?: number;\n}\n\nexport function useStepAttemptLogsQuery(\n stepId: string | undefined,\n attempt: number | undefined,\n options: UseStepAttemptLogsQueryOptions = {},\n) {\n const queryClient = useQueryClient();\n const missingStreamFailureCountRef = useRef(0);\n const missingStreamScopeRef = useRef<string | null>(null);\n const enabled = Boolean(stepId && attempt && Number.isInteger(attempt) && attempt > 0);\n const queryKey =\n enabled && stepId && attempt\n ? stepLogsQueryKeys.detail(stepId, attempt)\n : [...stepLogsQueryKeys.all, 'detail'];\n const missingStreamScope =\n enabled && stepId && attempt\n ? `${stepId}:${attempt}:${options.missingStreamRetryCount ?? 'unbounded'}`\n : null;\n if (missingStreamScopeRef.current !== missingStreamScope) {\n missingStreamScopeRef.current = missingStreamScope;\n missingStreamFailureCountRef.current = 0;\n }\n const initialErrorRetryCount = options.initialErrorRetryCount ?? 0;\n const initialErrorRetryDelayMs = options.initialErrorRetryDelayMs ?? STEP_LOG_LIVE_REFETCH_MS;\n const missingStreamRetryDelayMs = options.missingStreamRetryDelayMs ?? STEP_LOG_LIVE_REFETCH_MS;\n\n return useQuery({\n queryKey,\n enabled,\n queryFn: async ({signal}) => {\n const previous = queryClient.getQueryData<StepLogSnapshot>(queryKey);\n let response: ReadLogsResponseDto;\n try {\n response = await readStepAttemptLogsPage({\n stepId: stepId ?? '',\n attempt: attempt ?? 0,\n cursor: previous?.nextCursor ?? 0,\n signal,\n });\n } catch (error) {\n if (\n options.retryMissingStream &&\n previous === undefined &&\n isMissingStepLogStreamError(error)\n ) {\n const retryCount = options.missingStreamRetryCount;\n if (retryCount === undefined) throw error;\n if (missingStreamFailureCountRef.current >= retryCount) {\n return emptyCompleteLogSnapshot();\n }\n missingStreamFailureCountRef.current += 1;\n }\n throw error;\n }\n\n missingStreamFailureCountRef.current = 0;\n\n if (response.mode === 'presigned') {\n const ndjson = await readPresignedLogObject(response.url, signal);\n return mergeLogRead(previous, {mode: 'presigned', response, ndjson});\n }\n\n return mergeLogRead(previous, {mode: 'inline', response});\n },\n retry: (failureCount, error) => {\n if (initialErrorRetryCount <= 0) return false;\n if (queryClient.getQueryData<StepLogSnapshot>(queryKey) !== undefined) return false;\n if (options.retryMissingStream && isMissingStepLogStreamError(error)) return false;\n return failureCount < initialErrorRetryCount;\n },\n retryDelay: initialErrorRetryDelayMs,\n refetchInterval: (query) => {\n if (\n options.retryMissingStream &&\n query.state.data === undefined &&\n isMissingStepLogStreamError(query.state.error)\n ) {\n return missingStreamRetryDelayMs;\n }\n\n return stepLogRefetchInterval(query.state.data, query.state.status === 'error');\n },\n refetchIntervalInBackground: false,\n refetchOnMount: (query) => !query.state.data?.complete,\n refetchOnWindowFocus: (query) => !query.state.data?.complete,\n refetchOnReconnect: (query) => !query.state.data?.complete,\n });\n}\n\nfunction emptyCompleteLogSnapshot(): StepLogSnapshot {\n return {\n records: [],\n nextCursor: 0,\n source: 'inline',\n state: 'closed',\n complete: true,\n hasMore: false,\n truncated: false,\n totalBytes: null,\n expiresAt: null,\n };\n}\n"],"names":["ApiError","apiRequest","useQuery","useQueryClient","useRef","mergeLogRead","STEP_LOG_LIVE_REFETCH_MS","stepLogRefetchInterval","stepLogsQueryKeys","all","detail","stepId","attempt","readStepAttemptLogsPage","cursor","signal","params","URLSearchParams","String","encodeURIComponent","toString","StepLogObjectFetchError","Error","status","name","readPresignedLogObject","url","response","fetch","undefined","ok","text","isMissingStepLogStreamError","error","code","useStepAttemptLogsQuery","options","queryClient","missingStreamFailureCountRef","missingStreamScopeRef","enabled","Boolean","Number","isInteger","queryKey","missingStreamScope","missingStreamRetryCount","current","initialErrorRetryCount","initialErrorRetryDelayMs","missingStreamRetryDelayMs","queryFn","previous","getQueryData","nextCursor","retryMissingStream","retryCount","emptyCompleteLogSnapshot","mode","ndjson","retry","failureCount","retryDelay","refetchInterval","query","state","data","refetchIntervalInBackground","refetchOnMount","complete","refetchOnWindowFocus","refetchOnReconnect","records","source","hasMore","truncated","totalBytes","expiresAt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/step-logs.ts"],"sourcesContent":["import {readLogsResponseSchema} from '@shipfox/api-logs-dto';\nimport {ApiError, checkedApiRequest} from '@shipfox/client-api';\nimport {useQuery, useQueryClient} from '@tanstack/react-query';\nimport {useRef} from 'react';\nimport {\n mergeLogRead,\n STEP_LOG_LIVE_REFETCH_MS,\n type StepLogSnapshot,\n stepLogRefetchInterval,\n} from '#core/log-read.js';\nimport {parseLogNdjson, toLogRead} from './log-mapper.js';\n\nexport const stepLogsQueryKeys = {\n all: ['step-logs'] as const,\n detail: (stepId: string, attempt: number) =>\n [...stepLogsQueryKeys.all, 'detail', stepId, attempt] as const,\n};\n\ninterface ReadStepAttemptLogsPageParams {\n stepId: string;\n attempt: number;\n cursor: number;\n signal?: AbortSignal;\n}\n\nexport async function readStepAttemptLogsPage({\n stepId,\n attempt,\n cursor,\n signal,\n}: ReadStepAttemptLogsPageParams) {\n const params = new URLSearchParams({cursor: String(cursor)});\n const response = await checkedApiRequest(\n readLogsResponseSchema,\n `/steps/${encodeURIComponent(stepId)}/attempts/${attempt}/logs?${params.toString()}`,\n {signal},\n );\n return toLogRead(response);\n}\n\nclass StepLogObjectFetchError extends Error {\n readonly status: number;\n\n constructor(status: number) {\n super(`Could not load compacted logs (${status})`);\n this.name = 'StepLogObjectFetchError';\n this.status = status;\n }\n}\n\nasync function readPresignedLogObject(url: string, signal?: AbortSignal): Promise<string> {\n const response = await fetch(url, signal ? {signal} : undefined);\n if (!response.ok) throw new StepLogObjectFetchError(response.status);\n return await response.text();\n}\n\nexport function isMissingStepLogStreamError(error: unknown): boolean {\n return error instanceof ApiError && error.status === 404 && error.code === 'not-found';\n}\n\nexport interface UseStepAttemptLogsQueryOptions {\n retryMissingStream?: boolean;\n missingStreamRetryCount?: number | undefined;\n missingStreamRetryDelayMs?: number | undefined;\n initialErrorRetryCount?: number;\n initialErrorRetryDelayMs?: number;\n}\n\n/**\n * Narrow React Query wrapper for step logs. Its query function can read the prior\n * snapshot imperatively, but bounded missing-stream retries need a ref that resets\n * when the step, attempt, or retry budget changes. Keep that lifecycle state here\n * rather than exporting query options that could accidentally share it between views.\n */\nexport function useStepAttemptLogsQuery(\n stepId: string | undefined,\n attempt: number | undefined,\n options: UseStepAttemptLogsQueryOptions = {},\n) {\n const queryClient = useQueryClient();\n const missingStreamFailureCountRef = useRef(0);\n const missingStreamScopeRef = useRef<string | null>(null);\n const enabled = Boolean(stepId && attempt && Number.isInteger(attempt) && attempt > 0);\n const queryKey =\n enabled && stepId && attempt\n ? stepLogsQueryKeys.detail(stepId, attempt)\n : [...stepLogsQueryKeys.all, 'detail'];\n const missingStreamScope =\n enabled && stepId && attempt\n ? `${stepId}:${attempt}:${options.missingStreamRetryCount ?? 'unbounded'}`\n : null;\n if (missingStreamScopeRef.current !== missingStreamScope) {\n missingStreamScopeRef.current = missingStreamScope;\n missingStreamFailureCountRef.current = 0;\n }\n const initialErrorRetryCount = options.initialErrorRetryCount ?? 0;\n const initialErrorRetryDelayMs = options.initialErrorRetryDelayMs ?? STEP_LOG_LIVE_REFETCH_MS;\n const missingStreamRetryDelayMs = options.missingStreamRetryDelayMs ?? STEP_LOG_LIVE_REFETCH_MS;\n\n return useQuery({\n queryKey,\n enabled,\n queryFn: async ({signal}) => {\n const previous = queryClient.getQueryData<StepLogSnapshot>(queryKey);\n let response: Awaited<ReturnType<typeof readStepAttemptLogsPage>>;\n try {\n response = await readStepAttemptLogsPage({\n stepId: stepId ?? '',\n attempt: attempt ?? 0,\n cursor: previous?.nextCursor ?? 0,\n signal,\n });\n } catch (error) {\n if (\n options.retryMissingStream &&\n previous === undefined &&\n isMissingStepLogStreamError(error)\n ) {\n const retryCount = options.missingStreamRetryCount;\n if (retryCount === undefined) throw error;\n if (missingStreamFailureCountRef.current >= retryCount) {\n return emptyCompleteLogSnapshot();\n }\n missingStreamFailureCountRef.current += 1;\n }\n throw error;\n }\n\n missingStreamFailureCountRef.current = 0;\n\n if (response.mode === 'presigned') {\n const ndjson = await readPresignedLogObject(response.url, signal);\n return mergeLogRead(previous, {\n mode: 'presigned',\n response,\n records: parseLogNdjson(ndjson),\n });\n }\n\n return mergeLogRead(previous, {\n mode: 'inline',\n response,\n records: parseLogNdjson(response.ndjson),\n });\n },\n retry: (failureCount, error) => {\n if (initialErrorRetryCount <= 0) return false;\n if (queryClient.getQueryData<StepLogSnapshot>(queryKey) !== undefined) return false;\n if (options.retryMissingStream && isMissingStepLogStreamError(error)) return false;\n return failureCount < initialErrorRetryCount;\n },\n retryDelay: initialErrorRetryDelayMs,\n refetchInterval: (query) => {\n if (\n options.retryMissingStream &&\n query.state.data === undefined &&\n isMissingStepLogStreamError(query.state.error)\n ) {\n return missingStreamRetryDelayMs;\n }\n\n return stepLogRefetchInterval(query.state.data, query.state.status === 'error');\n },\n refetchIntervalInBackground: false,\n refetchOnMount: (query) => !query.state.data?.complete,\n refetchOnWindowFocus: (query) => !query.state.data?.complete,\n refetchOnReconnect: (query) => !query.state.data?.complete,\n });\n}\n\nfunction emptyCompleteLogSnapshot(): StepLogSnapshot {\n return {\n records: [],\n nextCursor: 0,\n source: 'inline',\n state: 'closed',\n complete: true,\n hasMore: false,\n truncated: false,\n totalBytes: null,\n expiresAt: null,\n };\n}\n"],"names":["readLogsResponseSchema","ApiError","checkedApiRequest","useQuery","useQueryClient","useRef","mergeLogRead","STEP_LOG_LIVE_REFETCH_MS","stepLogRefetchInterval","parseLogNdjson","toLogRead","stepLogsQueryKeys","all","detail","stepId","attempt","readStepAttemptLogsPage","cursor","signal","params","URLSearchParams","String","response","encodeURIComponent","toString","StepLogObjectFetchError","Error","status","name","readPresignedLogObject","url","fetch","undefined","ok","text","isMissingStepLogStreamError","error","code","useStepAttemptLogsQuery","options","queryClient","missingStreamFailureCountRef","missingStreamScopeRef","enabled","Boolean","Number","isInteger","queryKey","missingStreamScope","missingStreamRetryCount","current","initialErrorRetryCount","initialErrorRetryDelayMs","missingStreamRetryDelayMs","queryFn","previous","getQueryData","nextCursor","retryMissingStream","retryCount","emptyCompleteLogSnapshot","mode","ndjson","records","retry","failureCount","retryDelay","refetchInterval","query","state","data","refetchIntervalInBackground","refetchOnMount","complete","refetchOnWindowFocus","refetchOnReconnect","source","hasMore","truncated","totalBytes","expiresAt"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type { LogRecord, LogSource, LogState, SessionViewRow, SessionViewRowMeta, } from '#core/log-model.js';
|
|
1
2
|
export type { StepLogSnapshot } from '#core/log-read.js';
|
|
2
3
|
export { buildLogTree, type GroupLogNode, type LogNode, type LogTree, type MarkerLogNode, type OutputLogNode, type SessionLogNode, } from '#core/log-tree.js';
|
|
3
4
|
export * from './components/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,mBAAmB,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,8BAA8B,EACnC,uBAAuB,GACxB,MAAM,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,SAAS,EACT,QAAQ,EACR,cAAc,EACd,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,mBAAmB,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,8BAA8B,EACnC,uBAAuB,GACxB,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type {StepLogSnapshot} from '#core/log-read.js';\nexport {\n buildLogTree,\n type GroupLogNode,\n type LogNode,\n type LogTree,\n type MarkerLogNode,\n type OutputLogNode,\n type SessionLogNode,\n} from '#core/log-tree.js';\nexport * from './components/index.js';\nexport {\n isMissingStepLogStreamError,\n readStepAttemptLogsPage,\n stepLogsQueryKeys,\n type UseStepAttemptLogsQueryOptions,\n useStepAttemptLogsQuery,\n} from './hooks/api/step-logs.js';\n"],"names":["buildLogTree","isMissingStepLogStreamError","readStepAttemptLogsPage","stepLogsQueryKeys","useStepAttemptLogsQuery"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type {\n LogRecord,\n LogSource,\n LogState,\n SessionViewRow,\n SessionViewRowMeta,\n} from '#core/log-model.js';\nexport type {StepLogSnapshot} from '#core/log-read.js';\nexport {\n buildLogTree,\n type GroupLogNode,\n type LogNode,\n type LogTree,\n type MarkerLogNode,\n type OutputLogNode,\n type SessionLogNode,\n} from '#core/log-tree.js';\nexport * from './components/index.js';\nexport {\n isMissingStepLogStreamError,\n readStepAttemptLogsPage,\n stepLogsQueryKeys,\n type UseStepAttemptLogsQueryOptions,\n useStepAttemptLogsQuery,\n} from './hooks/api/step-logs.js';\n"],"names":["buildLogTree","isMissingStepLogStreamError","readStepAttemptLogsPage","stepLogsQueryKeys","useStepAttemptLogsQuery"],"mappings":"AAQA,SACEA,YAAY,QAOP,oBAAoB;AAC3B,cAAc,wBAAwB;AACtC,SACEC,2BAA2B,EAC3BC,uBAAuB,EACvBC,iBAAiB,EAEjBC,uBAAuB,QAClB,2BAA2B"}
|