@shipfox/client-logs 0.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.
Files changed (80) hide show
  1. package/.storybook/main.ts +1 -0
  2. package/.storybook/preview.css +9 -0
  3. package/.storybook/preview.tsx +56 -0
  4. package/.swcrc +42 -0
  5. package/.turbo/turbo-build.log +2 -0
  6. package/.turbo/turbo-type$colon$emit.log +1 -0
  7. package/.turbo/turbo-type.log +1 -0
  8. package/CHANGELOG.md +93 -0
  9. package/LICENSE +21 -0
  10. package/dist/components/agent-session-rows.d.ts +8 -0
  11. package/dist/components/agent-session-rows.d.ts.map +1 -0
  12. package/dist/components/agent-session-rows.js +374 -0
  13. package/dist/components/agent-session-rows.js.map +1 -0
  14. package/dist/components/index.d.ts +5 -0
  15. package/dist/components/index.d.ts.map +1 -0
  16. package/dist/components/index.js +6 -0
  17. package/dist/components/index.js.map +1 -0
  18. package/dist/components/log-group.d.ts +11 -0
  19. package/dist/components/log-group.d.ts.map +1 -0
  20. package/dist/components/log-group.js +57 -0
  21. package/dist/components/log-group.js.map +1 -0
  22. package/dist/components/log-view.d.ts +20 -0
  23. package/dist/components/log-view.d.ts.map +1 -0
  24. package/dist/components/log-view.js +243 -0
  25. package/dist/components/log-view.js.map +1 -0
  26. package/dist/components/output-log-row.d.ts +9 -0
  27. package/dist/components/output-log-row.d.ts.map +1 -0
  28. package/dist/components/output-log-row.js +24 -0
  29. package/dist/components/output-log-row.js.map +1 -0
  30. package/dist/components/system-markers.d.ts +21 -0
  31. package/dist/components/system-markers.d.ts.map +1 -0
  32. package/dist/components/system-markers.js +113 -0
  33. package/dist/components/system-markers.js.map +1 -0
  34. package/dist/core/log-read.d.ts +33 -0
  35. package/dist/core/log-read.d.ts.map +1 -0
  36. package/dist/core/log-read.js +49 -0
  37. package/dist/core/log-read.js.map +1 -0
  38. package/dist/core/log-tree.d.ts +85 -0
  39. package/dist/core/log-tree.d.ts.map +1 -0
  40. package/dist/core/log-tree.js +139 -0
  41. package/dist/core/log-tree.js.map +1 -0
  42. package/dist/env.d.js +2 -0
  43. package/dist/env.d.js.map +1 -0
  44. package/dist/hooks/api/step-logs.d.ts +24 -0
  45. package/dist/hooks/api/step-logs.d.ts.map +1 -0
  46. package/dist/hooks/api/step-logs.js +129 -0
  47. package/dist/hooks/api/step-logs.js.map +1 -0
  48. package/dist/index.d.ts +5 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +5 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/tsconfig.test.tsbuildinfo +1 -0
  53. package/package.json +84 -0
  54. package/src/components/agent-session-rows.tsx +341 -0
  55. package/src/components/index.ts +15 -0
  56. package/src/components/log-group.stories.tsx +204 -0
  57. package/src/components/log-group.tsx +54 -0
  58. package/src/components/log-view.stories.tsx +584 -0
  59. package/src/components/log-view.test.tsx +266 -0
  60. package/src/components/log-view.tsx +281 -0
  61. package/src/components/output-log-row.stories.tsx +76 -0
  62. package/src/components/output-log-row.tsx +35 -0
  63. package/src/components/system-markers.stories.tsx +46 -0
  64. package/src/components/system-markers.tsx +148 -0
  65. package/src/core/log-read.test.ts +219 -0
  66. package/src/core/log-read.ts +79 -0
  67. package/src/core/log-tree.test.ts +380 -0
  68. package/src/core/log-tree.ts +200 -0
  69. package/src/env.d.ts +7 -0
  70. package/src/hooks/api/step-logs-query.test.tsx +283 -0
  71. package/src/hooks/api/step-logs.test.ts +66 -0
  72. package/src/hooks/api/step-logs.ts +166 -0
  73. package/src/index.ts +18 -0
  74. package/test/setup.ts +3 -0
  75. package/tsconfig.build.json +9 -0
  76. package/tsconfig.build.tsbuildinfo +1 -0
  77. package/tsconfig.json +3 -0
  78. package/tsconfig.test.json +8 -0
  79. package/vercel.json +8 -0
  80. package/vitest.config.ts +70 -0
@@ -0,0 +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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"}
@@ -0,0 +1,5 @@
1
+ export type { StepLogSnapshot } from '#core/log-read.js';
2
+ export { buildLogTree, type GroupLogNode, type LogNode, type LogTree, type MarkerLogNode, type OutputLogNode, type SessionLogNode, } from '#core/log-tree.js';
3
+ export * from './components/index.js';
4
+ export { isMissingStepLogStreamError, readStepAttemptLogsPage, stepLogsQueryKeys, type UseStepAttemptLogsQueryOptions, useStepAttemptLogsQuery, } from './hooks/api/step-logs.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { buildLogTree } from '#core/log-tree.js';
2
+ export * from './components/index.js';
3
+ export { isMissingStepLogStreamError, readStepAttemptLogsPage, stepLogsQueryKeys, useStepAttemptLogsQuery } from './hooks/api/step-logs.js';
4
+
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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":"AACA,SACEA,YAAY,QAOP,oBAAoB;AAC3B,cAAc,wBAAwB;AACtC,SACEC,2BAA2B,EAC3BC,uBAAuB,EACvBC,iBAAiB,EAEjBC,uBAAuB,QAClB,2BAA2B"}