@herdctl/core 0.0.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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +219 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +51 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +251 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/config/index.html +191 -0
- package/coverage/src/config/index.ts.html +442 -0
- package/coverage/src/config/interpolate.ts.html +652 -0
- package/coverage/src/config/loader.ts.html +1501 -0
- package/coverage/src/config/merge.ts.html +823 -0
- package/coverage/src/config/parser.ts.html +1213 -0
- package/coverage/src/config/schema.ts.html +1123 -0
- package/coverage/src/fleet-manager/errors.ts.html +2326 -0
- package/coverage/src/fleet-manager/event-types.ts.html +1219 -0
- package/coverage/src/fleet-manager/fleet-manager.ts.html +7030 -0
- package/coverage/src/fleet-manager/index.html +206 -0
- package/coverage/src/fleet-manager/index.ts.html +469 -0
- package/coverage/src/fleet-manager/job-manager.ts.html +2074 -0
- package/coverage/src/fleet-manager/job-queue.ts.html +2479 -0
- package/coverage/src/fleet-manager/types.ts.html +2602 -0
- package/coverage/src/index.html +116 -0
- package/coverage/src/index.ts.html +181 -0
- package/coverage/src/runner/errors.ts.html +1006 -0
- package/coverage/src/runner/index.html +191 -0
- package/coverage/src/runner/index.ts.html +256 -0
- package/coverage/src/runner/job-executor.ts.html +1429 -0
- package/coverage/src/runner/message-processor.ts.html +1150 -0
- package/coverage/src/runner/sdk-adapter.ts.html +658 -0
- package/coverage/src/runner/types.ts.html +559 -0
- package/coverage/src/scheduler/errors.ts.html +388 -0
- package/coverage/src/scheduler/index.html +206 -0
- package/coverage/src/scheduler/index.ts.html +244 -0
- package/coverage/src/scheduler/interval.ts.html +652 -0
- package/coverage/src/scheduler/schedule-runner.ts.html +1411 -0
- package/coverage/src/scheduler/schedule-state.ts.html +718 -0
- package/coverage/src/scheduler/scheduler.ts.html +1795 -0
- package/coverage/src/scheduler/types.ts.html +733 -0
- package/coverage/src/state/directory.ts.html +736 -0
- package/coverage/src/state/errors.ts.html +376 -0
- package/coverage/src/state/fleet-state.ts.html +937 -0
- package/coverage/src/state/index.html +221 -0
- package/coverage/src/state/index.ts.html +322 -0
- package/coverage/src/state/job-metadata.ts.html +1420 -0
- package/coverage/src/state/job-output.ts.html +1033 -0
- package/coverage/src/state/schemas/fleet-state.ts.html +445 -0
- package/coverage/src/state/schemas/index.html +176 -0
- package/coverage/src/state/schemas/index.ts.html +286 -0
- package/coverage/src/state/schemas/job-metadata.ts.html +628 -0
- package/coverage/src/state/schemas/job-output.ts.html +616 -0
- package/coverage/src/state/schemas/session-info.ts.html +361 -0
- package/coverage/src/state/session.ts.html +844 -0
- package/coverage/src/state/types.ts.html +262 -0
- package/coverage/src/state/utils/atomic.ts.html +748 -0
- package/coverage/src/state/utils/index.html +146 -0
- package/coverage/src/state/utils/index.ts.html +103 -0
- package/coverage/src/state/utils/reads.ts.html +1621 -0
- package/coverage/src/work-sources/adapters/github.ts.html +3583 -0
- package/coverage/src/work-sources/adapters/index.html +131 -0
- package/coverage/src/work-sources/adapters/index.ts.html +277 -0
- package/coverage/src/work-sources/errors.ts.html +298 -0
- package/coverage/src/work-sources/index.html +176 -0
- package/coverage/src/work-sources/index.ts.html +529 -0
- package/coverage/src/work-sources/manager.ts.html +1324 -0
- package/coverage/src/work-sources/registry.ts.html +619 -0
- package/coverage/src/work-sources/types.ts.html +568 -0
- package/dist/config/__tests__/agent.test.d.ts +2 -0
- package/dist/config/__tests__/agent.test.d.ts.map +1 -0
- package/dist/config/__tests__/agent.test.js +752 -0
- package/dist/config/__tests__/agent.test.js.map +1 -0
- package/dist/config/__tests__/interpolate.test.d.ts +2 -0
- package/dist/config/__tests__/interpolate.test.d.ts.map +1 -0
- package/dist/config/__tests__/interpolate.test.js +509 -0
- package/dist/config/__tests__/interpolate.test.js.map +1 -0
- package/dist/config/__tests__/loader.test.d.ts +2 -0
- package/dist/config/__tests__/loader.test.d.ts.map +1 -0
- package/dist/config/__tests__/loader.test.js +631 -0
- package/dist/config/__tests__/loader.test.js.map +1 -0
- package/dist/config/__tests__/merge.test.d.ts +2 -0
- package/dist/config/__tests__/merge.test.d.ts.map +1 -0
- package/dist/config/__tests__/merge.test.js +672 -0
- package/dist/config/__tests__/merge.test.js.map +1 -0
- package/dist/config/__tests__/parser.test.d.ts +2 -0
- package/dist/config/__tests__/parser.test.d.ts.map +1 -0
- package/dist/config/__tests__/parser.test.js +476 -0
- package/dist/config/__tests__/parser.test.js.map +1 -0
- package/dist/config/__tests__/schema.test.d.ts +2 -0
- package/dist/config/__tests__/schema.test.d.ts.map +1 -0
- package/dist/config/__tests__/schema.test.js +776 -0
- package/dist/config/__tests__/schema.test.js.map +1 -0
- package/dist/config/index.d.ts +11 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +26 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/interpolate.d.ts +76 -0
- package/dist/config/interpolate.d.ts.map +1 -0
- package/dist/config/interpolate.js +143 -0
- package/dist/config/interpolate.js.map +1 -0
- package/dist/config/loader.d.ts +147 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +336 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/merge.d.ts +84 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +138 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/config/parser.d.ts +143 -0
- package/dist/config/parser.d.ts.map +1 -0
- package/dist/config/parser.js +316 -0
- package/dist/config/parser.js.map +1 -0
- package/dist/config/schema.d.ts +1906 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +268 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/fleet-manager/__tests__/coverage.test.d.ts +13 -0
- package/dist/fleet-manager/__tests__/coverage.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/coverage.test.js +2282 -0
- package/dist/fleet-manager/__tests__/coverage.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/errors.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/errors.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/errors.test.js +557 -0
- package/dist/fleet-manager/__tests__/errors.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/event-helpers.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/event-helpers.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/event-helpers.test.js +368 -0
- package/dist/fleet-manager/__tests__/event-helpers.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/integration.test.d.ts +11 -0
- package/dist/fleet-manager/__tests__/integration.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/integration.test.js +949 -0
- package/dist/fleet-manager/__tests__/integration.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/job-control.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/job-control.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/job-control.test.js +215 -0
- package/dist/fleet-manager/__tests__/job-control.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/job-manager.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/job-manager.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/job-manager.test.js +659 -0
- package/dist/fleet-manager/__tests__/job-manager.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/job-queue.test.d.ts +5 -0
- package/dist/fleet-manager/__tests__/job-queue.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/job-queue.test.js +315 -0
- package/dist/fleet-manager/__tests__/job-queue.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/reload.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/reload.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/reload.test.js +609 -0
- package/dist/fleet-manager/__tests__/reload.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/status-queries.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/status-queries.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/status-queries.test.js +488 -0
- package/dist/fleet-manager/__tests__/status-queries.test.js.map +1 -0
- package/dist/fleet-manager/__tests__/trigger.test.d.ts +7 -0
- package/dist/fleet-manager/__tests__/trigger.test.d.ts.map +1 -0
- package/dist/fleet-manager/__tests__/trigger.test.js +471 -0
- package/dist/fleet-manager/__tests__/trigger.test.js.map +1 -0
- package/dist/fleet-manager/errors.d.ts +407 -0
- package/dist/fleet-manager/errors.d.ts.map +1 -0
- package/dist/fleet-manager/errors.js +569 -0
- package/dist/fleet-manager/errors.js.map +1 -0
- package/dist/fleet-manager/event-types.d.ts +302 -0
- package/dist/fleet-manager/event-types.d.ts.map +1 -0
- package/dist/fleet-manager/event-types.js +9 -0
- package/dist/fleet-manager/event-types.js.map +1 -0
- package/dist/fleet-manager/fleet-manager.d.ts +699 -0
- package/dist/fleet-manager/fleet-manager.d.ts.map +1 -0
- package/dist/fleet-manager/fleet-manager.js +1906 -0
- package/dist/fleet-manager/fleet-manager.js.map +1 -0
- package/dist/fleet-manager/index.d.ts +17 -0
- package/dist/fleet-manager/index.d.ts.map +1 -0
- package/dist/fleet-manager/index.js +29 -0
- package/dist/fleet-manager/index.js.map +1 -0
- package/dist/fleet-manager/job-manager.d.ts +271 -0
- package/dist/fleet-manager/job-manager.d.ts.map +1 -0
- package/dist/fleet-manager/job-manager.js +443 -0
- package/dist/fleet-manager/job-manager.js.map +1 -0
- package/dist/fleet-manager/job-queue.d.ts +422 -0
- package/dist/fleet-manager/job-queue.d.ts.map +1 -0
- package/dist/fleet-manager/job-queue.js +448 -0
- package/dist/fleet-manager/job-queue.js.map +1 -0
- package/dist/fleet-manager/types.d.ts +680 -0
- package/dist/fleet-manager/types.d.ts.map +1 -0
- package/dist/fleet-manager/types.js +8 -0
- package/dist/fleet-manager/types.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/runner/__tests__/errors.test.d.ts +2 -0
- package/dist/runner/__tests__/errors.test.d.ts.map +1 -0
- package/dist/runner/__tests__/errors.test.js +264 -0
- package/dist/runner/__tests__/errors.test.js.map +1 -0
- package/dist/runner/__tests__/job-executor.test.d.ts +2 -0
- package/dist/runner/__tests__/job-executor.test.d.ts.map +1 -0
- package/dist/runner/__tests__/job-executor.test.js +1345 -0
- package/dist/runner/__tests__/job-executor.test.js.map +1 -0
- package/dist/runner/__tests__/message-processor.test.d.ts +2 -0
- package/dist/runner/__tests__/message-processor.test.d.ts.map +1 -0
- package/dist/runner/__tests__/message-processor.test.js +768 -0
- package/dist/runner/__tests__/message-processor.test.js.map +1 -0
- package/dist/runner/__tests__/sdk-adapter.test.d.ts +2 -0
- package/dist/runner/__tests__/sdk-adapter.test.d.ts.map +1 -0
- package/dist/runner/__tests__/sdk-adapter.test.js +554 -0
- package/dist/runner/__tests__/sdk-adapter.test.js.map +1 -0
- package/dist/runner/errors.d.ts +121 -0
- package/dist/runner/errors.d.ts.map +1 -0
- package/dist/runner/errors.js +212 -0
- package/dist/runner/errors.js.map +1 -0
- package/dist/runner/index.d.ts +12 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +15 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/job-executor.d.ts +98 -0
- package/dist/runner/job-executor.d.ts.map +1 -0
- package/dist/runner/job-executor.js +333 -0
- package/dist/runner/job-executor.js.map +1 -0
- package/dist/runner/message-processor.d.ts +45 -0
- package/dist/runner/message-processor.d.ts.map +1 -0
- package/dist/runner/message-processor.js +294 -0
- package/dist/runner/message-processor.js.map +1 -0
- package/dist/runner/sdk-adapter.d.ts +60 -0
- package/dist/runner/sdk-adapter.d.ts.map +1 -0
- package/dist/runner/sdk-adapter.js +138 -0
- package/dist/runner/sdk-adapter.js.map +1 -0
- package/dist/runner/types.d.ts +135 -0
- package/dist/runner/types.d.ts.map +1 -0
- package/dist/runner/types.js +7 -0
- package/dist/runner/types.js.map +1 -0
- package/dist/scheduler/__tests__/errors.test.d.ts +2 -0
- package/dist/scheduler/__tests__/errors.test.d.ts.map +1 -0
- package/dist/scheduler/__tests__/errors.test.js +101 -0
- package/dist/scheduler/__tests__/errors.test.js.map +1 -0
- package/dist/scheduler/__tests__/interval.test.d.ts +2 -0
- package/dist/scheduler/__tests__/interval.test.d.ts.map +1 -0
- package/dist/scheduler/__tests__/interval.test.js +419 -0
- package/dist/scheduler/__tests__/interval.test.js.map +1 -0
- package/dist/scheduler/__tests__/schedule-runner.test.d.ts +2 -0
- package/dist/scheduler/__tests__/schedule-runner.test.d.ts.map +1 -0
- package/dist/scheduler/__tests__/schedule-runner.test.js +634 -0
- package/dist/scheduler/__tests__/schedule-runner.test.js.map +1 -0
- package/dist/scheduler/__tests__/schedule-state.test.d.ts +2 -0
- package/dist/scheduler/__tests__/schedule-state.test.d.ts.map +1 -0
- package/dist/scheduler/__tests__/schedule-state.test.js +572 -0
- package/dist/scheduler/__tests__/schedule-state.test.js.map +1 -0
- package/dist/scheduler/__tests__/scheduler.test.d.ts +2 -0
- package/dist/scheduler/__tests__/scheduler.test.d.ts.map +1 -0
- package/dist/scheduler/__tests__/scheduler.test.js +987 -0
- package/dist/scheduler/__tests__/scheduler.test.js.map +1 -0
- package/dist/scheduler/errors.d.ts +61 -0
- package/dist/scheduler/errors.d.ts.map +1 -0
- package/dist/scheduler/errors.js +81 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/index.d.ts +13 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +17 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/interval.d.ts +64 -0
- package/dist/scheduler/interval.d.ts.map +1 -0
- package/dist/scheduler/interval.js +139 -0
- package/dist/scheduler/interval.js.map +1 -0
- package/dist/scheduler/schedule-runner.d.ts +149 -0
- package/dist/scheduler/schedule-runner.d.ts.map +1 -0
- package/dist/scheduler/schedule-runner.js +277 -0
- package/dist/scheduler/schedule-runner.js.map +1 -0
- package/dist/scheduler/schedule-state.d.ts +105 -0
- package/dist/scheduler/schedule-state.d.ts.map +1 -0
- package/dist/scheduler/schedule-state.js +151 -0
- package/dist/scheduler/schedule-state.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +138 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -0
- package/dist/scheduler/scheduler.js +423 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/types.d.ts +160 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/scheduler/types.js +8 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/state/__tests__/directory.test.d.ts +2 -0
- package/dist/state/__tests__/directory.test.d.ts.map +1 -0
- package/dist/state/__tests__/directory.test.js +414 -0
- package/dist/state/__tests__/directory.test.js.map +1 -0
- package/dist/state/__tests__/fleet-state.test.d.ts +2 -0
- package/dist/state/__tests__/fleet-state.test.d.ts.map +1 -0
- package/dist/state/__tests__/fleet-state.test.js +696 -0
- package/dist/state/__tests__/fleet-state.test.js.map +1 -0
- package/dist/state/__tests__/job-metadata-schema.test.d.ts +2 -0
- package/dist/state/__tests__/job-metadata-schema.test.d.ts.map +1 -0
- package/dist/state/__tests__/job-metadata-schema.test.js +329 -0
- package/dist/state/__tests__/job-metadata-schema.test.js.map +1 -0
- package/dist/state/__tests__/job-metadata.test.d.ts +2 -0
- package/dist/state/__tests__/job-metadata.test.d.ts.map +1 -0
- package/dist/state/__tests__/job-metadata.test.js +667 -0
- package/dist/state/__tests__/job-metadata.test.js.map +1 -0
- package/dist/state/__tests__/job-output.test.d.ts +2 -0
- package/dist/state/__tests__/job-output.test.d.ts.map +1 -0
- package/dist/state/__tests__/job-output.test.js +672 -0
- package/dist/state/__tests__/job-output.test.js.map +1 -0
- package/dist/state/__tests__/session-schema.test.d.ts +2 -0
- package/dist/state/__tests__/session-schema.test.d.ts.map +1 -0
- package/dist/state/__tests__/session-schema.test.js +323 -0
- package/dist/state/__tests__/session-schema.test.js.map +1 -0
- package/dist/state/__tests__/session.test.d.ts +2 -0
- package/dist/state/__tests__/session.test.d.ts.map +1 -0
- package/dist/state/__tests__/session.test.js +468 -0
- package/dist/state/__tests__/session.test.js.map +1 -0
- package/dist/state/directory.d.ts +42 -0
- package/dist/state/directory.d.ts.map +1 -0
- package/dist/state/directory.js +170 -0
- package/dist/state/directory.js.map +1 -0
- package/dist/state/errors.d.ts +44 -0
- package/dist/state/errors.d.ts.map +1 -0
- package/dist/state/errors.js +82 -0
- package/dist/state/errors.js.map +1 -0
- package/dist/state/fleet-state.d.ts +126 -0
- package/dist/state/fleet-state.d.ts.map +1 -0
- package/dist/state/fleet-state.js +196 -0
- package/dist/state/fleet-state.js.map +1 -0
- package/dist/state/index.d.ts +21 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +30 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/job-metadata.d.ts +151 -0
- package/dist/state/job-metadata.d.ts.map +1 -0
- package/dist/state/job-metadata.js +287 -0
- package/dist/state/job-metadata.js.map +1 -0
- package/dist/state/job-output.d.ts +116 -0
- package/dist/state/job-output.d.ts.map +1 -0
- package/dist/state/job-output.js +218 -0
- package/dist/state/job-output.js.map +1 -0
- package/dist/state/schemas/__tests__/job-output.test.d.ts +2 -0
- package/dist/state/schemas/__tests__/job-output.test.d.ts.map +1 -0
- package/dist/state/schemas/__tests__/job-output.test.js +279 -0
- package/dist/state/schemas/__tests__/job-output.test.js.map +1 -0
- package/dist/state/schemas/fleet-state.d.ts +249 -0
- package/dist/state/schemas/fleet-state.d.ts.map +1 -0
- package/dist/state/schemas/fleet-state.js +97 -0
- package/dist/state/schemas/fleet-state.js.map +1 -0
- package/dist/state/schemas/index.d.ts +10 -0
- package/dist/state/schemas/index.d.ts.map +1 -0
- package/dist/state/schemas/index.js +10 -0
- package/dist/state/schemas/index.js.map +1 -0
- package/dist/state/schemas/job-metadata.d.ts +118 -0
- package/dist/state/schemas/job-metadata.d.ts.map +1 -0
- package/dist/state/schemas/job-metadata.js +123 -0
- package/dist/state/schemas/job-metadata.js.map +1 -0
- package/dist/state/schemas/job-output.d.ts +291 -0
- package/dist/state/schemas/job-output.d.ts.map +1 -0
- package/dist/state/schemas/job-output.js +132 -0
- package/dist/state/schemas/job-output.js.map +1 -0
- package/dist/state/schemas/session-info.d.ts +65 -0
- package/dist/state/schemas/session-info.d.ts.map +1 -0
- package/dist/state/schemas/session-info.js +58 -0
- package/dist/state/schemas/session-info.js.map +1 -0
- package/dist/state/session.d.ts +92 -0
- package/dist/state/session.d.ts.map +1 -0
- package/dist/state/session.js +173 -0
- package/dist/state/session.js.map +1 -0
- package/dist/state/types.d.ts +54 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +18 -0
- package/dist/state/types.js.map +1 -0
- package/dist/state/utils/__tests__/atomic.test.d.ts +2 -0
- package/dist/state/utils/__tests__/atomic.test.d.ts.map +1 -0
- package/dist/state/utils/__tests__/atomic.test.js +537 -0
- package/dist/state/utils/__tests__/atomic.test.js.map +1 -0
- package/dist/state/utils/__tests__/reads.test.d.ts +2 -0
- package/dist/state/utils/__tests__/reads.test.d.ts.map +1 -0
- package/dist/state/utils/__tests__/reads.test.js +792 -0
- package/dist/state/utils/__tests__/reads.test.js.map +1 -0
- package/dist/state/utils/atomic.d.ts +89 -0
- package/dist/state/utils/atomic.d.ts.map +1 -0
- package/dist/state/utils/atomic.js +157 -0
- package/dist/state/utils/atomic.js.map +1 -0
- package/dist/state/utils/index.d.ts +6 -0
- package/dist/state/utils/index.d.ts.map +1 -0
- package/dist/state/utils/index.js +6 -0
- package/dist/state/utils/index.js.map +1 -0
- package/dist/state/utils/reads.d.ts +196 -0
- package/dist/state/utils/reads.d.ts.map +1 -0
- package/dist/state/utils/reads.js +346 -0
- package/dist/state/utils/reads.js.map +1 -0
- package/dist/work-sources/__tests__/github.test.d.ts +2 -0
- package/dist/work-sources/__tests__/github.test.d.ts.map +1 -0
- package/dist/work-sources/__tests__/github.test.js +1334 -0
- package/dist/work-sources/__tests__/github.test.js.map +1 -0
- package/dist/work-sources/__tests__/manager.test.d.ts +2 -0
- package/dist/work-sources/__tests__/manager.test.d.ts.map +1 -0
- package/dist/work-sources/__tests__/manager.test.js +424 -0
- package/dist/work-sources/__tests__/manager.test.js.map +1 -0
- package/dist/work-sources/__tests__/registry.test.d.ts +2 -0
- package/dist/work-sources/__tests__/registry.test.d.ts.map +1 -0
- package/dist/work-sources/__tests__/registry.test.js +381 -0
- package/dist/work-sources/__tests__/registry.test.js.map +1 -0
- package/dist/work-sources/__tests__/types.test.d.ts +2 -0
- package/dist/work-sources/__tests__/types.test.d.ts.map +1 -0
- package/dist/work-sources/__tests__/types.test.js +406 -0
- package/dist/work-sources/__tests__/types.test.js.map +1 -0
- package/dist/work-sources/adapters/github.d.ts +290 -0
- package/dist/work-sources/adapters/github.d.ts.map +1 -0
- package/dist/work-sources/adapters/github.js +803 -0
- package/dist/work-sources/adapters/github.js.map +1 -0
- package/dist/work-sources/adapters/index.d.ts +10 -0
- package/dist/work-sources/adapters/index.d.ts.map +1 -0
- package/dist/work-sources/adapters/index.js +31 -0
- package/dist/work-sources/adapters/index.js.map +1 -0
- package/dist/work-sources/errors.d.ts +40 -0
- package/dist/work-sources/errors.d.ts.map +1 -0
- package/dist/work-sources/errors.js +54 -0
- package/dist/work-sources/errors.js.map +1 -0
- package/dist/work-sources/index.d.ts +105 -0
- package/dist/work-sources/index.d.ts.map +1 -0
- package/dist/work-sources/index.js +24 -0
- package/dist/work-sources/index.js.map +1 -0
- package/dist/work-sources/manager.d.ts +370 -0
- package/dist/work-sources/manager.d.ts.map +1 -0
- package/dist/work-sources/manager.js +61 -0
- package/dist/work-sources/manager.js.map +1 -0
- package/dist/work-sources/registry.d.ts +128 -0
- package/dist/work-sources/registry.d.ts.map +1 -0
- package/dist/work-sources/registry.js +132 -0
- package/dist/work-sources/registry.js.map +1 -0
- package/dist/work-sources/types.d.ts +127 -0
- package/dist/work-sources/types.d.ts.map +1 -0
- package/dist/work-sources/types.js +8 -0
- package/dist/work-sources/types.js.map +1 -0
- package/package.json +23 -0
- package/src/config/__tests__/agent.test.ts +864 -0
- package/src/config/__tests__/interpolate.test.ts +644 -0
- package/src/config/__tests__/loader.test.ts +784 -0
- package/src/config/__tests__/merge.test.ts +751 -0
- package/src/config/__tests__/parser.test.ts +533 -0
- package/src/config/__tests__/schema.test.ts +873 -0
- package/src/config/index.ts +119 -0
- package/src/config/interpolate.ts +189 -0
- package/src/config/loader.ts +472 -0
- package/src/config/merge.ts +246 -0
- package/src/config/parser.ts +376 -0
- package/src/config/schema.ts +346 -0
- package/src/fleet-manager/__tests__/coverage.test.ts +2869 -0
- package/src/fleet-manager/__tests__/errors.test.ts +660 -0
- package/src/fleet-manager/__tests__/event-helpers.test.ts +448 -0
- package/src/fleet-manager/__tests__/integration.test.ts +1209 -0
- package/src/fleet-manager/__tests__/job-control.test.ts +283 -0
- package/src/fleet-manager/__tests__/job-manager.test.ts +869 -0
- package/src/fleet-manager/__tests__/job-queue.test.ts +401 -0
- package/src/fleet-manager/__tests__/reload.test.ts +751 -0
- package/src/fleet-manager/__tests__/status-queries.test.ts +595 -0
- package/src/fleet-manager/__tests__/trigger.test.ts +601 -0
- package/src/fleet-manager/errors.ts +747 -0
- package/src/fleet-manager/event-types.ts +378 -0
- package/src/fleet-manager/fleet-manager.ts +2315 -0
- package/src/fleet-manager/index.ts +128 -0
- package/src/fleet-manager/job-manager.ts +663 -0
- package/src/fleet-manager/job-queue.ts +798 -0
- package/src/fleet-manager/types.ts +839 -0
- package/src/index.ts +32 -0
- package/src/runner/__tests__/errors.test.ts +382 -0
- package/src/runner/__tests__/job-executor.test.ts +1708 -0
- package/src/runner/__tests__/message-processor.test.ts +960 -0
- package/src/runner/__tests__/sdk-adapter.test.ts +626 -0
- package/src/runner/errors.ts +307 -0
- package/src/runner/index.ts +57 -0
- package/src/runner/job-executor.ts +448 -0
- package/src/runner/message-processor.ts +355 -0
- package/src/runner/sdk-adapter.ts +191 -0
- package/src/runner/types.ts +158 -0
- package/src/scheduler/__tests__/errors.test.ts +159 -0
- package/src/scheduler/__tests__/interval.test.ts +515 -0
- package/src/scheduler/__tests__/schedule-runner.test.ts +798 -0
- package/src/scheduler/__tests__/schedule-state.test.ts +671 -0
- package/src/scheduler/__tests__/scheduler.test.ts +1280 -0
- package/src/scheduler/errors.ts +101 -0
- package/src/scheduler/index.ts +53 -0
- package/src/scheduler/interval.ts +189 -0
- package/src/scheduler/schedule-runner.ts +442 -0
- package/src/scheduler/schedule-state.ts +211 -0
- package/src/scheduler/scheduler.ts +570 -0
- package/src/scheduler/types.ts +216 -0
- package/src/state/__tests__/directory.test.ts +595 -0
- package/src/state/__tests__/fleet-state.test.ts +868 -0
- package/src/state/__tests__/job-metadata-schema.test.ts +414 -0
- package/src/state/__tests__/job-metadata.test.ts +831 -0
- package/src/state/__tests__/job-output.test.ts +856 -0
- package/src/state/__tests__/session-schema.test.ts +378 -0
- package/src/state/__tests__/session.test.ts +604 -0
- package/src/state/directory.ts +217 -0
- package/src/state/errors.ts +97 -0
- package/src/state/fleet-state.ts +284 -0
- package/src/state/index.ts +79 -0
- package/src/state/job-metadata.ts +445 -0
- package/src/state/job-output.ts +316 -0
- package/src/state/schemas/__tests__/job-output.test.ts +338 -0
- package/src/state/schemas/fleet-state.ts +120 -0
- package/src/state/schemas/index.ts +67 -0
- package/src/state/schemas/job-metadata.ts +181 -0
- package/src/state/schemas/job-output.ts +177 -0
- package/src/state/schemas/session-info.ts +92 -0
- package/src/state/session.ts +253 -0
- package/src/state/types.ts +59 -0
- package/src/state/utils/__tests__/atomic.test.ts +723 -0
- package/src/state/utils/__tests__/reads.test.ts +1071 -0
- package/src/state/utils/atomic.ts +221 -0
- package/src/state/utils/index.ts +6 -0
- package/src/state/utils/reads.ts +512 -0
- package/src/work-sources/__tests__/github.test.ts +1800 -0
- package/src/work-sources/__tests__/manager.test.ts +529 -0
- package/src/work-sources/__tests__/registry.test.ts +477 -0
- package/src/work-sources/__tests__/types.test.ts +479 -0
- package/src/work-sources/adapters/github.ts +1166 -0
- package/src/work-sources/adapters/index.ts +64 -0
- package/src/work-sources/errors.ts +71 -0
- package/src/work-sources/index.ts +148 -0
- package/src/work-sources/manager.ts +413 -0
- package/src/work-sources/registry.ts +178 -0
- package/src/work-sources/types.ts +161 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +19 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe concurrent read utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides read operations that handle concurrent access safely.
|
|
5
|
+
* Read operations don't require locks - multiple readers can access
|
|
6
|
+
* files simultaneously. These utilities handle edge cases like:
|
|
7
|
+
* - Files being written to during read (retry on partial read)
|
|
8
|
+
* - Empty or truncated YAML files
|
|
9
|
+
* - Incomplete last lines in JSONL files
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { parse as parseYaml, YAMLParseError } from "yaml";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Error thrown when a safe read operation fails
|
|
17
|
+
*/
|
|
18
|
+
export class SafeReadError extends Error {
|
|
19
|
+
public readonly path: string;
|
|
20
|
+
public readonly code?: string;
|
|
21
|
+
|
|
22
|
+
constructor(message: string, path: string, cause?: Error) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "SafeReadError";
|
|
25
|
+
this.path = path;
|
|
26
|
+
this.cause = cause;
|
|
27
|
+
this.code = (cause as NodeJS.ErrnoException | undefined)?.code;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Options for safe read operations
|
|
33
|
+
*/
|
|
34
|
+
export interface SafeReadOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Maximum number of retry attempts for transient failures.
|
|
37
|
+
* Default: 3
|
|
38
|
+
*/
|
|
39
|
+
maxRetries?: number;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Base delay in milliseconds between retries.
|
|
43
|
+
* Uses exponential backoff: delay = baseDelayMs * 2^attempt
|
|
44
|
+
* Default: 10
|
|
45
|
+
*/
|
|
46
|
+
baseDelayMs?: number;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Injectable read function for testing
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
readFn?: (path: string, encoding: BufferEncoding) => Promise<string>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Options for safeReadJsonl
|
|
57
|
+
*/
|
|
58
|
+
export interface SafeReadJsonlOptions extends SafeReadOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Whether to skip invalid JSON lines instead of failing.
|
|
61
|
+
* Default: false - only skips truly incomplete last line
|
|
62
|
+
*/
|
|
63
|
+
skipInvalidLines?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Result type for safe YAML read operations
|
|
68
|
+
*/
|
|
69
|
+
export type SafeReadYamlResult<T> =
|
|
70
|
+
| { success: true; data: T }
|
|
71
|
+
| { success: false; error: SafeReadError };
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Result type for safe JSONL read operations
|
|
75
|
+
*/
|
|
76
|
+
export type SafeReadJsonlResult<T> =
|
|
77
|
+
| { success: true; data: T[]; skippedLines: number }
|
|
78
|
+
| { success: false; error: SafeReadError };
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check if an error is likely a transient read error that should be retried.
|
|
82
|
+
* This happens when reading a file while it's being written atomically.
|
|
83
|
+
*
|
|
84
|
+
* We treat YAML parse errors as potentially transient because:
|
|
85
|
+
* 1. If a read occurs during an atomic write, the file might be empty or partially written
|
|
86
|
+
* 2. The retry gives time for the atomic rename to complete
|
|
87
|
+
* 3. Non-transient errors (like truly malformed YAML) will fail consistently
|
|
88
|
+
*/
|
|
89
|
+
function isTransientReadError(error: unknown): boolean {
|
|
90
|
+
if (!(error instanceof Error)) return false;
|
|
91
|
+
|
|
92
|
+
// All YAML parse errors are potentially transient - they could indicate
|
|
93
|
+
// a partial read during an atomic write operation
|
|
94
|
+
if (error instanceof YAMLParseError) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// JSON parse errors for incomplete content
|
|
99
|
+
if (error instanceof SyntaxError) {
|
|
100
|
+
const msg = error.message.toLowerCase();
|
|
101
|
+
if (
|
|
102
|
+
msg.includes("unexpected end") ||
|
|
103
|
+
msg.includes("unexpected token") ||
|
|
104
|
+
msg.includes("unterminated")
|
|
105
|
+
) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Wait for a delay using exponential backoff
|
|
115
|
+
*/
|
|
116
|
+
async function backoffDelay(attempt: number, baseDelayMs: number): Promise<void> {
|
|
117
|
+
const delay = baseDelayMs * Math.pow(2, attempt);
|
|
118
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Read and parse a YAML file safely with retry logic.
|
|
123
|
+
*
|
|
124
|
+
* This function handles:
|
|
125
|
+
* - Files being written to during read (retries on parse failure)
|
|
126
|
+
* - Empty files (returns null/undefined based on YAML spec)
|
|
127
|
+
* - Truncated files (retries then fails gracefully)
|
|
128
|
+
*
|
|
129
|
+
* Read operations don't require locks - multiple concurrent reads are safe.
|
|
130
|
+
* The retry logic handles the case where a read occurs during an atomic write.
|
|
131
|
+
*
|
|
132
|
+
* @param filePath - Path to the YAML file
|
|
133
|
+
* @param options - Read options including retry configuration
|
|
134
|
+
* @returns Promise resolving to SafeReadYamlResult with success/failure
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const result = await safeReadYaml<MyConfig>('/path/to/config.yaml');
|
|
139
|
+
* if (result.success) {
|
|
140
|
+
* console.log(result.data);
|
|
141
|
+
* } else {
|
|
142
|
+
* console.error(result.error.message);
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export async function safeReadYaml<T = unknown>(
|
|
147
|
+
filePath: string,
|
|
148
|
+
options: SafeReadOptions = {}
|
|
149
|
+
): Promise<SafeReadYamlResult<T>> {
|
|
150
|
+
const {
|
|
151
|
+
maxRetries = 3,
|
|
152
|
+
baseDelayMs = 10,
|
|
153
|
+
readFn = (path, encoding) => readFile(path, encoding),
|
|
154
|
+
} = options;
|
|
155
|
+
|
|
156
|
+
let lastError: Error | undefined;
|
|
157
|
+
|
|
158
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
159
|
+
try {
|
|
160
|
+
const content = await readFn(filePath, "utf-8");
|
|
161
|
+
|
|
162
|
+
// Handle empty file - YAML spec says empty doc is null
|
|
163
|
+
if (content.trim() === "") {
|
|
164
|
+
return { success: true, data: null as T };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const parsed = parseYaml(content) as T;
|
|
168
|
+
return { success: true, data: parsed };
|
|
169
|
+
} catch (error) {
|
|
170
|
+
lastError = error as Error;
|
|
171
|
+
|
|
172
|
+
// File not found or permission errors are not transient
|
|
173
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
174
|
+
if (code === "ENOENT" || code === "EACCES" || code === "EPERM") {
|
|
175
|
+
return {
|
|
176
|
+
success: false,
|
|
177
|
+
error: new SafeReadError(
|
|
178
|
+
`Failed to read YAML file ${filePath}: ${(error as Error).message}`,
|
|
179
|
+
filePath,
|
|
180
|
+
error as Error
|
|
181
|
+
),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check if this is a transient error worth retrying
|
|
186
|
+
if (isTransientReadError(error) && attempt < maxRetries) {
|
|
187
|
+
await backoffDelay(attempt, baseDelayMs);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Non-transient error or retries exhausted
|
|
192
|
+
return {
|
|
193
|
+
success: false,
|
|
194
|
+
error: new SafeReadError(
|
|
195
|
+
`Failed to parse YAML file ${filePath}: ${(error as Error).message}`,
|
|
196
|
+
filePath,
|
|
197
|
+
error as Error
|
|
198
|
+
),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Should not reach here, but handle it just in case
|
|
204
|
+
return {
|
|
205
|
+
success: false,
|
|
206
|
+
error: new SafeReadError(
|
|
207
|
+
`Failed to read YAML file ${filePath} after ${maxRetries + 1} attempts`,
|
|
208
|
+
filePath,
|
|
209
|
+
lastError
|
|
210
|
+
),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Read and parse a JSONL file safely, handling incomplete last lines.
|
|
216
|
+
*
|
|
217
|
+
* This function handles:
|
|
218
|
+
* - Incomplete last line (truncates to last valid line)
|
|
219
|
+
* - Empty files (returns empty array)
|
|
220
|
+
* - Files being written to during read (retries on failure)
|
|
221
|
+
*
|
|
222
|
+
* JSONL (JSON Lines) format has one JSON object per line. When reading
|
|
223
|
+
* a file that's being appended to, the last line may be incomplete.
|
|
224
|
+
* This function safely truncates to the last complete line.
|
|
225
|
+
*
|
|
226
|
+
* Read operations don't require locks - multiple concurrent reads are safe.
|
|
227
|
+
*
|
|
228
|
+
* @param filePath - Path to the JSONL file
|
|
229
|
+
* @param options - Read options including retry configuration
|
|
230
|
+
* @returns Promise resolving to SafeReadJsonlResult with array of parsed objects
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* const result = await safeReadJsonl<LogEntry>('/path/to/events.jsonl');
|
|
235
|
+
* if (result.success) {
|
|
236
|
+
* console.log(`Read ${result.data.length} entries, skipped ${result.skippedLines}`);
|
|
237
|
+
* }
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
export async function safeReadJsonl<T = unknown>(
|
|
241
|
+
filePath: string,
|
|
242
|
+
options: SafeReadJsonlOptions = {}
|
|
243
|
+
): Promise<SafeReadJsonlResult<T>> {
|
|
244
|
+
const {
|
|
245
|
+
maxRetries = 3,
|
|
246
|
+
baseDelayMs = 10,
|
|
247
|
+
skipInvalidLines = false,
|
|
248
|
+
readFn = (path, encoding) => readFile(path, encoding),
|
|
249
|
+
} = options;
|
|
250
|
+
|
|
251
|
+
let lastError: Error | undefined;
|
|
252
|
+
|
|
253
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
254
|
+
try {
|
|
255
|
+
const content = await readFn(filePath, "utf-8");
|
|
256
|
+
|
|
257
|
+
// Handle empty file
|
|
258
|
+
if (content.trim() === "") {
|
|
259
|
+
return { success: true, data: [], skippedLines: 0 };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const result = parseJsonlContent<T>(content, skipInvalidLines);
|
|
263
|
+
return { success: true, ...result };
|
|
264
|
+
} catch (error) {
|
|
265
|
+
lastError = error as Error;
|
|
266
|
+
|
|
267
|
+
// File not found or permission errors are not transient
|
|
268
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
269
|
+
if (code === "ENOENT" || code === "EACCES" || code === "EPERM") {
|
|
270
|
+
return {
|
|
271
|
+
success: false,
|
|
272
|
+
error: new SafeReadError(
|
|
273
|
+
`Failed to read JSONL file ${filePath}: ${(error as Error).message}`,
|
|
274
|
+
filePath,
|
|
275
|
+
error as Error
|
|
276
|
+
),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Retry on transient errors
|
|
281
|
+
if (attempt < maxRetries) {
|
|
282
|
+
await backoffDelay(attempt, baseDelayMs);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
error: new SafeReadError(
|
|
291
|
+
`Failed to read JSONL file ${filePath} after ${maxRetries + 1} attempts`,
|
|
292
|
+
filePath,
|
|
293
|
+
lastError
|
|
294
|
+
),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Parse JSONL content, handling incomplete last line.
|
|
300
|
+
*
|
|
301
|
+
* @internal
|
|
302
|
+
*/
|
|
303
|
+
function parseJsonlContent<T>(
|
|
304
|
+
content: string,
|
|
305
|
+
skipInvalidLines: boolean
|
|
306
|
+
): { data: T[]; skippedLines: number } {
|
|
307
|
+
const lines = content.split("\n");
|
|
308
|
+
const result: T[] = [];
|
|
309
|
+
let skippedLines = 0;
|
|
310
|
+
|
|
311
|
+
for (let i = 0; i < lines.length; i++) {
|
|
312
|
+
const line = lines[i].trim();
|
|
313
|
+
|
|
314
|
+
// Skip empty lines
|
|
315
|
+
if (line === "") {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const parsed = JSON.parse(line) as T;
|
|
321
|
+
result.push(parsed);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
// Last line may be incomplete - always skip it silently
|
|
324
|
+
if (i === lines.length - 1 || i === lines.length - 2) {
|
|
325
|
+
// Could be the actual last line or second-to-last if file ends with \n
|
|
326
|
+
skippedLines++;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// For middle lines, either skip or fail based on option
|
|
331
|
+
if (skipInvalidLines) {
|
|
332
|
+
skippedLines++;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Re-throw for non-last-line errors when not skipping
|
|
337
|
+
throw new SafeReadError(
|
|
338
|
+
`Invalid JSON on line ${i + 1}: ${(error as Error).message}`,
|
|
339
|
+
"",
|
|
340
|
+
error as Error
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return { data: result, skippedLines };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Read a YAML file with retry logic, throwing on failure.
|
|
350
|
+
*
|
|
351
|
+
* This is a convenience wrapper around safeReadYaml that throws
|
|
352
|
+
* instead of returning a result object.
|
|
353
|
+
*
|
|
354
|
+
* @param filePath - Path to the YAML file
|
|
355
|
+
* @param options - Read options
|
|
356
|
+
* @returns Promise resolving to parsed YAML content
|
|
357
|
+
* @throws SafeReadError on failure
|
|
358
|
+
*/
|
|
359
|
+
export async function readYaml<T = unknown>(
|
|
360
|
+
filePath: string,
|
|
361
|
+
options: SafeReadOptions = {}
|
|
362
|
+
): Promise<T> {
|
|
363
|
+
const result = await safeReadYaml<T>(filePath, options);
|
|
364
|
+
if (!result.success) {
|
|
365
|
+
throw result.error;
|
|
366
|
+
}
|
|
367
|
+
return result.data;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Read a JSONL file, handling incomplete last line, throwing on failure.
|
|
372
|
+
*
|
|
373
|
+
* This is a convenience wrapper around safeReadJsonl that throws
|
|
374
|
+
* instead of returning a result object.
|
|
375
|
+
*
|
|
376
|
+
* @param filePath - Path to the JSONL file
|
|
377
|
+
* @param options - Read options
|
|
378
|
+
* @returns Promise resolving to array of parsed objects
|
|
379
|
+
* @throws SafeReadError on failure
|
|
380
|
+
*/
|
|
381
|
+
export async function readJsonl<T = unknown>(
|
|
382
|
+
filePath: string,
|
|
383
|
+
options: SafeReadJsonlOptions = {}
|
|
384
|
+
): Promise<T[]> {
|
|
385
|
+
const result = await safeReadJsonl<T>(filePath, options);
|
|
386
|
+
if (!result.success) {
|
|
387
|
+
throw result.error;
|
|
388
|
+
}
|
|
389
|
+
return result.data;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Result type for safe JSON read operations
|
|
394
|
+
*/
|
|
395
|
+
export type SafeReadJsonResult<T> =
|
|
396
|
+
| { success: true; data: T }
|
|
397
|
+
| { success: false; error: SafeReadError };
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Read and parse a JSON file safely with retry logic.
|
|
401
|
+
*
|
|
402
|
+
* This function handles:
|
|
403
|
+
* - Files being written to during read (retries on parse failure)
|
|
404
|
+
* - Empty files (returns null)
|
|
405
|
+
* - Truncated files (retries then fails gracefully)
|
|
406
|
+
*
|
|
407
|
+
* Read operations don't require locks - multiple concurrent reads are safe.
|
|
408
|
+
* The retry logic handles the case where a read occurs during an atomic write.
|
|
409
|
+
*
|
|
410
|
+
* @param filePath - Path to the JSON file
|
|
411
|
+
* @param options - Read options including retry configuration
|
|
412
|
+
* @returns Promise resolving to SafeReadJsonResult with success/failure
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```typescript
|
|
416
|
+
* const result = await safeReadJson<MyConfig>('/path/to/config.json');
|
|
417
|
+
* if (result.success) {
|
|
418
|
+
* console.log(result.data);
|
|
419
|
+
* } else {
|
|
420
|
+
* console.error(result.error.message);
|
|
421
|
+
* }
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
export async function safeReadJson<T = unknown>(
|
|
425
|
+
filePath: string,
|
|
426
|
+
options: SafeReadOptions = {}
|
|
427
|
+
): Promise<SafeReadJsonResult<T>> {
|
|
428
|
+
const {
|
|
429
|
+
maxRetries = 3,
|
|
430
|
+
baseDelayMs = 10,
|
|
431
|
+
readFn = (path, encoding) => readFile(path, encoding),
|
|
432
|
+
} = options;
|
|
433
|
+
|
|
434
|
+
let lastError: Error | undefined;
|
|
435
|
+
|
|
436
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
437
|
+
try {
|
|
438
|
+
const content = await readFn(filePath, "utf-8");
|
|
439
|
+
|
|
440
|
+
// Handle empty file
|
|
441
|
+
if (content.trim() === "") {
|
|
442
|
+
return { success: true, data: null as T };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const parsed = JSON.parse(content) as T;
|
|
446
|
+
return { success: true, data: parsed };
|
|
447
|
+
} catch (error) {
|
|
448
|
+
lastError = error as Error;
|
|
449
|
+
|
|
450
|
+
// File not found or permission errors are not transient
|
|
451
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
452
|
+
if (code === "ENOENT" || code === "EACCES" || code === "EPERM") {
|
|
453
|
+
return {
|
|
454
|
+
success: false,
|
|
455
|
+
error: new SafeReadError(
|
|
456
|
+
`Failed to read JSON file ${filePath}: ${(error as Error).message}`,
|
|
457
|
+
filePath,
|
|
458
|
+
error as Error
|
|
459
|
+
),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Check if this is a transient error worth retrying
|
|
464
|
+
if (isTransientReadError(error) && attempt < maxRetries) {
|
|
465
|
+
await backoffDelay(attempt, baseDelayMs);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Non-transient error or retries exhausted
|
|
470
|
+
return {
|
|
471
|
+
success: false,
|
|
472
|
+
error: new SafeReadError(
|
|
473
|
+
`Failed to parse JSON file ${filePath}: ${(error as Error).message}`,
|
|
474
|
+
filePath,
|
|
475
|
+
error as Error
|
|
476
|
+
),
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Should not reach here, but handle it just in case
|
|
482
|
+
return {
|
|
483
|
+
success: false,
|
|
484
|
+
error: new SafeReadError(
|
|
485
|
+
`Failed to read JSON file ${filePath} after ${maxRetries + 1} attempts`,
|
|
486
|
+
filePath,
|
|
487
|
+
lastError
|
|
488
|
+
),
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Read a JSON file with retry logic, throwing on failure.
|
|
494
|
+
*
|
|
495
|
+
* This is a convenience wrapper around safeReadJson that throws
|
|
496
|
+
* instead of returning a result object.
|
|
497
|
+
*
|
|
498
|
+
* @param filePath - Path to the JSON file
|
|
499
|
+
* @param options - Read options
|
|
500
|
+
* @returns Promise resolving to parsed JSON content
|
|
501
|
+
* @throws SafeReadError on failure
|
|
502
|
+
*/
|
|
503
|
+
export async function readJson<T = unknown>(
|
|
504
|
+
filePath: string,
|
|
505
|
+
options: SafeReadOptions = {}
|
|
506
|
+
): Promise<T> {
|
|
507
|
+
const result = await safeReadJson<T>(filePath, options);
|
|
508
|
+
if (!result.success) {
|
|
509
|
+
throw result.error;
|
|
510
|
+
}
|
|
511
|
+
return result.data;
|
|
512
|
+
}
|