@warlock.js/ai 4.4.0 → 4.6.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/CHANGELOG.md +63 -52
- package/cjs/index.cjs +240 -14147
- package/cjs/src-Bmajk4Qg.cjs +30 -0
- package/cjs/src-OZyDYHxm.cjs +25089 -0
- package/cjs/src-OZyDYHxm.cjs.map +1 -0
- package/esm/agent/agent-config.type.d.mts +119 -1
- package/esm/agent/agent-config.type.d.mts.map +1 -1
- package/esm/agent/agent-input-builder.mjs +27 -6
- package/esm/agent/agent-input-builder.mjs.map +1 -1
- package/esm/agent/agent.d.mts +40 -1
- package/esm/agent/agent.d.mts.map +1 -1
- package/esm/agent/agent.mjs +328 -36
- package/esm/agent/agent.mjs.map +1 -1
- package/esm/agent/index.d.mts +2 -1
- package/esm/agent/index.mjs +1 -0
- package/esm/agent/judge-config.type.d.mts +33 -0
- package/esm/agent/judge-config.type.d.mts.map +1 -0
- package/esm/agent/judge-config.type.mjs +13 -0
- package/esm/agent/judge-config.type.mjs.map +1 -0
- package/esm/agent/signature.mjs +57 -0
- package/esm/agent/signature.mjs.map +1 -0
- package/esm/agent/snapshot.mjs +101 -0
- package/esm/agent/snapshot.mjs.map +1 -0
- package/esm/ai-openai/src/embedder.mjs +4 -0
- package/esm/ai-openai/src/image.mjs +5 -0
- package/esm/ai-openai/src/index.mjs +7 -0
- package/esm/ai-openai/src/model.mjs +5 -0
- package/esm/ai-openai/src/sdk.mjs +9 -0
- package/esm/ai-openai/src/speech.mjs +5 -0
- package/esm/ai-openai/src/transcription.mjs +6 -0
- package/esm/ai-openai/src/utils/index.mjs +5 -0
- package/esm/ai-openai/src/utils/to-openai-messages.mjs +3 -0
- package/esm/ai-openai/src/utils/to-openai-tools.mjs +3 -0
- package/esm/ai-openai/src/utils/wrap-openai-error.mjs +4 -0
- package/esm/ai.d.mts +164 -53
- package/esm/ai.d.mts.map +1 -1
- package/esm/ai.mjs +79 -8
- package/esm/ai.mjs.map +1 -1
- package/esm/batch/batch.d.mts.map +1 -1
- package/esm/batch/batch.mjs +21 -1
- package/esm/batch/batch.mjs.map +1 -1
- package/esm/batch/batch.type.d.mts +11 -4
- package/esm/batch/batch.type.d.mts.map +1 -1
- package/esm/config.d.mts +39 -3
- package/esm/config.d.mts.map +1 -1
- package/esm/config.mjs +26 -2
- package/esm/config.mjs.map +1 -1
- package/esm/contracts/agent/agent-options.type.d.mts +33 -5
- package/esm/contracts/agent/agent-options.type.d.mts.map +1 -1
- package/esm/contracts/agent/agent-snapshot.type.d.mts +90 -0
- package/esm/contracts/agent/agent-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/agent/agent.contract.d.mts +29 -1
- package/esm/contracts/agent/agent.contract.d.mts.map +1 -1
- package/esm/contracts/agent/eval.type.d.mts +43 -2
- package/esm/contracts/agent/eval.type.d.mts.map +1 -1
- package/esm/contracts/agent/index.d.mts +2 -1
- package/esm/contracts/attachment-policy.type.d.mts +51 -0
- package/esm/contracts/attachment-policy.type.d.mts.map +1 -0
- package/esm/contracts/attachment.type.d.mts +16 -7
- package/esm/contracts/attachment.type.d.mts.map +1 -1
- package/esm/contracts/content-part.type.d.mts +14 -5
- package/esm/contracts/content-part.type.d.mts.map +1 -1
- package/esm/contracts/events/supervisor-events.type.d.mts.map +1 -1
- package/esm/contracts/image-model.contract.d.mts +156 -0
- package/esm/contracts/image-model.contract.d.mts.map +1 -0
- package/esm/contracts/index.d.mts +13 -6
- package/esm/contracts/model.contract.d.mts +11 -8
- package/esm/contracts/model.contract.d.mts.map +1 -1
- package/esm/contracts/orchestrator/index.d.mts +1 -0
- package/esm/contracts/orchestrator/orchestrator-config.type.d.mts +31 -2
- package/esm/contracts/orchestrator/orchestrator-config.type.d.mts.map +1 -1
- package/esm/contracts/orchestrator/session-lock.contract.d.mts +47 -0
- package/esm/contracts/orchestrator/session-lock.contract.d.mts.map +1 -0
- package/esm/contracts/planner/index.d.mts +3 -2
- package/esm/contracts/planner/planner-config.type.d.mts +61 -0
- package/esm/contracts/planner/planner-config.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner-execute-options.type.d.mts +60 -1
- package/esm/contracts/planner/planner-execute-options.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner-result.type.d.mts +8 -0
- package/esm/contracts/planner/planner-result.type.d.mts.map +1 -1
- package/esm/contracts/planner/planner-snapshot.type.d.mts +77 -0
- package/esm/contracts/planner/planner-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/planner/planner.contract.d.mts +21 -1
- package/esm/contracts/planner/planner.contract.d.mts.map +1 -1
- package/esm/contracts/result/agent-result.type.d.mts +6 -4
- package/esm/contracts/result/agent-result.type.d.mts.map +1 -1
- package/esm/contracts/result/base-report.type.d.mts +21 -3
- package/esm/contracts/result/base-report.type.d.mts.map +1 -1
- package/esm/contracts/result/base-report.type.mjs.map +1 -1
- package/esm/contracts/result/execution-report.type.d.mts +53 -1
- package/esm/contracts/result/execution-report.type.d.mts.map +1 -1
- package/esm/contracts/result/supervisor-result.type.d.mts +14 -2
- package/esm/contracts/result/supervisor-result.type.d.mts.map +1 -1
- package/esm/contracts/result/workflow-result.type.d.mts +2 -1
- package/esm/contracts/result/workflow-result.type.d.mts.map +1 -1
- package/esm/contracts/sdk-adapter.contract.d.mts +37 -0
- package/esm/contracts/sdk-adapter.contract.d.mts.map +1 -1
- package/esm/contracts/speech-model.contract.d.mts +97 -0
- package/esm/contracts/speech-model.contract.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor-config.type.d.mts +29 -0
- package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -1
- package/esm/contracts/system-prompt.contract.d.mts +103 -1
- package/esm/contracts/system-prompt.contract.d.mts.map +1 -1
- package/esm/contracts/team/index.d.mts +1 -0
- package/esm/contracts/team/team-config.type.d.mts +127 -0
- package/esm/contracts/team/team-config.type.d.mts.map +1 -0
- package/esm/contracts/tool.contract.d.mts +4 -2
- package/esm/contracts/tool.contract.d.mts.map +1 -1
- package/esm/contracts/transcription-model.contract.d.mts +101 -0
- package/esm/contracts/transcription-model.contract.d.mts.map +1 -0
- package/esm/contracts/workflow/step.contract.d.mts +30 -5
- package/esm/contracts/workflow/step.contract.d.mts.map +1 -1
- package/esm/contracts/workflow/workflow.contract.d.mts +16 -0
- package/esm/contracts/workflow/workflow.contract.d.mts.map +1 -1
- package/esm/errors/agent-drift-error.d.mts +32 -0
- package/esm/errors/agent-drift-error.d.mts.map +1 -0
- package/esm/errors/agent-drift-error.mjs +31 -0
- package/esm/errors/agent-drift-error.mjs.map +1 -0
- package/esm/errors/error-code.type.d.mts +1 -1
- package/esm/errors/index.d.mts +3 -0
- package/esm/errors/index.mjs +3 -0
- package/esm/errors/outbound-policy-error.d.mts +27 -0
- package/esm/errors/outbound-policy-error.d.mts.map +1 -0
- package/esm/errors/outbound-policy-error.mjs +32 -0
- package/esm/errors/outbound-policy-error.mjs.map +1 -0
- package/esm/errors/planner-drift-error.d.mts +34 -0
- package/esm/errors/planner-drift-error.d.mts.map +1 -0
- package/esm/errors/planner-drift-error.mjs +33 -0
- package/esm/errors/planner-drift-error.mjs.map +1 -0
- package/esm/eval/dataset.d.mts +28 -0
- package/esm/eval/dataset.d.mts.map +1 -0
- package/esm/eval/dataset.mjs +112 -0
- package/esm/eval/dataset.mjs.map +1 -0
- package/esm/eval/dataset.type.d.mts +53 -0
- package/esm/eval/dataset.type.d.mts.map +1 -0
- package/esm/eval/eval-runner.d.mts.map +1 -1
- package/esm/eval/eval-runner.mjs +16 -2
- package/esm/eval/eval-runner.mjs.map +1 -1
- package/esm/eval/index.d.mts +20 -1
- package/esm/eval/index.d.mts.map +1 -1
- package/esm/eval/index.mjs +20 -2
- package/esm/eval/index.mjs.map +1 -1
- package/esm/eval/regression.d.mts +30 -0
- package/esm/eval/regression.d.mts.map +1 -0
- package/esm/eval/regression.mjs +51 -0
- package/esm/eval/regression.mjs.map +1 -0
- package/esm/eval/report-json.d.mts +30 -0
- package/esm/eval/report-json.d.mts.map +1 -0
- package/esm/eval/report-json.mjs +33 -0
- package/esm/eval/report-json.mjs.map +1 -0
- package/esm/eval/report-junit.d.mts +22 -0
- package/esm/eval/report-junit.d.mts.map +1 -0
- package/esm/eval/report-junit.mjs +60 -0
- package/esm/eval/report-junit.mjs.map +1 -0
- package/esm/guard/contracts/guard-options.type.d.mts +165 -0
- package/esm/guard/contracts/guard-options.type.d.mts.map +1 -0
- package/esm/guard/contracts/guardrail.contract.d.mts +78 -0
- package/esm/guard/contracts/guardrail.contract.d.mts.map +1 -0
- package/esm/guard/contracts/index.d.mts +4 -0
- package/esm/guard/contracts/openai-client.contract.d.mts +51 -0
- package/esm/guard/contracts/openai-client.contract.d.mts.map +1 -0
- package/esm/guard/contracts/verdict.type.d.mts +76 -0
- package/esm/guard/contracts/verdict.type.d.mts.map +1 -0
- package/esm/guard/detectors/index.d.mts +4 -0
- package/esm/guard/detectors/index.mjs +6 -0
- package/esm/guard/detectors/injection.d.mts +34 -0
- package/esm/guard/detectors/injection.d.mts.map +1 -0
- package/esm/guard/detectors/injection.mjs +254 -0
- package/esm/guard/detectors/injection.mjs.map +1 -0
- package/esm/guard/detectors/moderation.d.mts +32 -0
- package/esm/guard/detectors/moderation.d.mts.map +1 -0
- package/esm/guard/detectors/moderation.mjs +134 -0
- package/esm/guard/detectors/moderation.mjs.map +1 -0
- package/esm/guard/detectors/pii.d.mts +41 -0
- package/esm/guard/detectors/pii.d.mts.map +1 -0
- package/esm/guard/detectors/pii.mjs +199 -0
- package/esm/guard/detectors/pii.mjs.map +1 -0
- package/esm/guard/detectors/topic.d.mts +29 -0
- package/esm/guard/detectors/topic.d.mts.map +1 -0
- package/esm/guard/detectors/topic.mjs +99 -0
- package/esm/guard/detectors/topic.mjs.map +1 -0
- package/esm/guard/errors.d.mts +12 -0
- package/esm/guard/errors.d.mts.map +1 -0
- package/esm/guard/errors.mjs +18 -0
- package/esm/guard/errors.mjs.map +1 -0
- package/esm/guard/guard.d.mts +67 -0
- package/esm/guard/guard.d.mts.map +1 -0
- package/esm/guard/guard.mjs +209 -0
- package/esm/guard/guard.mjs.map +1 -0
- package/esm/guard/guardrail.d.mts +39 -0
- package/esm/guard/guardrail.d.mts.map +1 -0
- package/esm/guard/guardrail.mjs +22 -0
- package/esm/guard/guardrail.mjs.map +1 -0
- package/esm/human/contracts/approval.type.d.mts +154 -0
- package/esm/human/contracts/approval.type.d.mts.map +1 -0
- package/esm/human/contracts/human-approval.type.d.mts +38 -0
- package/esm/human/contracts/human-approval.type.d.mts.map +1 -0
- package/esm/human/contracts/index.d.mts +4 -0
- package/esm/human/contracts/interrupt-store.contract.d.mts +112 -0
- package/esm/human/contracts/interrupt-store.contract.d.mts.map +1 -0
- package/esm/human/contracts/resume.type.d.mts +77 -0
- package/esm/human/contracts/resume.type.d.mts.map +1 -0
- package/esm/human/errors.d.mts +84 -0
- package/esm/human/errors.d.mts.map +1 -0
- package/esm/human/errors.mjs +60 -0
- package/esm/human/errors.mjs.map +1 -0
- package/esm/human/human-approval.d.mts +57 -0
- package/esm/human/human-approval.d.mts.map +1 -0
- package/esm/human/human-approval.mjs +170 -0
- package/esm/human/human-approval.mjs.map +1 -0
- package/esm/human/policy.d.mts +55 -0
- package/esm/human/policy.d.mts.map +1 -0
- package/esm/human/policy.mjs +67 -0
- package/esm/human/policy.mjs.map +1 -0
- package/esm/human/register.mjs +37 -0
- package/esm/human/register.mjs.map +1 -0
- package/esm/human/resume-seed.mjs +53 -0
- package/esm/human/resume-seed.mjs.map +1 -0
- package/esm/human/resume.d.mts +54 -0
- package/esm/human/resume.d.mts.map +1 -0
- package/esm/human/resume.mjs +121 -0
- package/esm/human/resume.mjs.map +1 -0
- package/esm/human/stores/index.mjs +5 -0
- package/esm/human/stores/memory.d.mts +30 -0
- package/esm/human/stores/memory.d.mts.map +1 -0
- package/esm/human/stores/memory.mjs +91 -0
- package/esm/human/stores/memory.mjs.map +1 -0
- package/esm/human/stores/pg.d.mts +59 -0
- package/esm/human/stores/pg.d.mts.map +1 -0
- package/esm/human/stores/pg.mjs +220 -0
- package/esm/human/stores/pg.mjs.map +1 -0
- package/esm/human/stores/redis.d.mts +56 -0
- package/esm/human/stores/redis.d.mts.map +1 -0
- package/esm/human/stores/redis.mjs +201 -0
- package/esm/human/stores/redis.mjs.map +1 -0
- package/esm/image/image-cost.d.mts +32 -0
- package/esm/image/image-cost.d.mts.map +1 -0
- package/esm/image/image-cost.mjs +55 -0
- package/esm/image/image-cost.mjs.map +1 -0
- package/esm/image/image.d.mts +92 -0
- package/esm/image/image.d.mts.map +1 -0
- package/esm/image/image.mjs +113 -0
- package/esm/image/image.mjs.map +1 -0
- package/esm/image/index.mjs +4 -0
- package/esm/index.d.mts +137 -24
- package/esm/index.mjs +101 -11
- package/esm/middleware/builtins/budget.mjs +6 -2
- package/esm/middleware/builtins/budget.mjs.map +1 -1
- package/esm/middleware/utils/extract-user-text.d.mts +8 -1
- package/esm/middleware/utils/extract-user-text.d.mts.map +1 -1
- package/esm/middleware/utils/extract-user-text.mjs +8 -1
- package/esm/middleware/utils/extract-user-text.mjs.map +1 -1
- package/esm/mock/index.d.mts +3 -0
- package/esm/mock/index.mjs +3 -0
- package/esm/mock/mock-config.type.d.mts +22 -0
- package/esm/mock/mock-config.type.d.mts.map +1 -1
- package/esm/mock/mock-image-model.d.mts +41 -0
- package/esm/mock/mock-image-model.d.mts.map +1 -0
- package/esm/mock/mock-image-model.mjs +52 -0
- package/esm/mock/mock-image-model.mjs.map +1 -0
- package/esm/mock/mock-sdk.d.mts +7 -1
- package/esm/mock/mock-sdk.d.mts.map +1 -1
- package/esm/mock/mock-sdk.mjs +27 -0
- package/esm/mock/mock-sdk.mjs.map +1 -1
- package/esm/mock/mock-speech-model.d.mts +31 -0
- package/esm/mock/mock-speech-model.d.mts.map +1 -0
- package/esm/mock/mock-speech-model.mjs +39 -0
- package/esm/mock/mock-speech-model.mjs.map +1 -0
- package/esm/mock/mock-transcription-model.d.mts +32 -0
- package/esm/mock/mock-transcription-model.d.mts.map +1 -0
- package/esm/mock/mock-transcription-model.mjs +36 -0
- package/esm/mock/mock-transcription-model.mjs.map +1 -0
- package/esm/object-stream/index.d.mts +2 -0
- package/esm/object-stream/index.mjs +4 -0
- package/esm/object-stream/parse-partial-json.d.mts +22 -0
- package/esm/object-stream/parse-partial-json.d.mts.map +1 -0
- package/esm/object-stream/parse-partial-json.mjs +78 -0
- package/esm/object-stream/parse-partial-json.mjs.map +1 -0
- package/esm/object-stream/stream-object.d.mts +68 -0
- package/esm/object-stream/stream-object.d.mts.map +1 -0
- package/esm/object-stream/stream-object.mjs +104 -0
- package/esm/object-stream/stream-object.mjs.map +1 -0
- package/esm/observe/index.mjs +4 -0
- package/esm/observe/observer-registry.d.mts +30 -0
- package/esm/observe/observer-registry.d.mts.map +1 -0
- package/esm/observe/observer-registry.mjs +51 -0
- package/esm/observe/observer-registry.mjs.map +1 -0
- package/esm/observe/observer.contract.d.mts +40 -0
- package/esm/observe/observer.contract.d.mts.map +1 -0
- package/esm/observe/resolve-observers.d.mts +40 -0
- package/esm/observe/resolve-observers.d.mts.map +1 -0
- package/esm/observe/resolve-observers.mjs +73 -0
- package/esm/observe/resolve-observers.mjs.map +1 -0
- package/esm/orchestrator/execution.d.mts.map +1 -1
- package/esm/orchestrator/execution.mjs +5 -2
- package/esm/orchestrator/execution.mjs.map +1 -1
- package/esm/orchestrator/index.d.mts +1 -0
- package/esm/orchestrator/index.mjs +1 -0
- package/esm/orchestrator/orchestrator.d.mts.map +1 -1
- package/esm/orchestrator/orchestrator.mjs +39 -6
- package/esm/orchestrator/orchestrator.mjs.map +1 -1
- package/esm/orchestrator/session-lock.d.mts +25 -0
- package/esm/orchestrator/session-lock.d.mts.map +1 -0
- package/esm/orchestrator/session-lock.mjs +83 -0
- package/esm/orchestrator/session-lock.mjs.map +1 -0
- package/esm/planner/dag-scheduler.mjs +97 -0
- package/esm/planner/dag-scheduler.mjs.map +1 -0
- package/esm/planner/plan-prompt.d.mts +1 -1
- package/esm/planner/plan-prompt.d.mts.map +1 -1
- package/esm/planner/plan-prompt.mjs +2 -1
- package/esm/planner/plan-prompt.mjs.map +1 -1
- package/esm/planner/planner-run.d.mts +8 -0
- package/esm/planner/planner-run.d.mts.map +1 -1
- package/esm/planner/planner-run.mjs +457 -31
- package/esm/planner/planner-run.mjs.map +1 -1
- package/esm/planner/planner.d.mts.map +1 -1
- package/esm/planner/planner.mjs +26 -2
- package/esm/planner/planner.mjs.map +1 -1
- package/esm/planner/snapshot.mjs +95 -0
- package/esm/planner/snapshot.mjs.map +1 -0
- package/esm/prompt/errors.d.mts +57 -0
- package/esm/prompt/errors.d.mts.map +1 -0
- package/esm/prompt/errors.mjs +73 -0
- package/esm/prompt/errors.mjs.map +1 -0
- package/esm/prompt/index.d.mts +3 -0
- package/esm/prompt/index.mjs +4 -0
- package/esm/prompt/prompt-langfuse-sync.mjs +104 -0
- package/esm/prompt/prompt-langfuse-sync.mjs.map +1 -0
- package/esm/prompt/prompt-langfuse-sync.type.d.mts +32 -0
- package/esm/prompt/prompt-langfuse-sync.type.d.mts.map +1 -0
- package/esm/prompt/prompt-validate.mjs +170 -0
- package/esm/prompt/prompt-validate.mjs.map +1 -0
- package/esm/prompt/prompt.d.mts +54 -0
- package/esm/prompt/prompt.d.mts.map +1 -0
- package/esm/prompt/prompt.mjs +218 -0
- package/esm/prompt/prompt.mjs.map +1 -0
- package/esm/prompt/prompt.type.d.mts +174 -0
- package/esm/prompt/prompt.type.d.mts.map +1 -0
- package/esm/prompts/index.d.mts +3 -0
- package/esm/prompts/index.mjs +3 -0
- package/esm/prompts/prompts-manager.contract.d.mts +154 -0
- package/esm/prompts/prompts-manager.contract.d.mts.map +1 -0
- package/esm/prompts/prompts-manager.d.mts +38 -0
- package/esm/prompts/prompts-manager.d.mts.map +1 -0
- package/esm/prompts/prompts-manager.mjs +410 -0
- package/esm/prompts/prompts-manager.mjs.map +1 -0
- package/esm/prompts/prompts-manager.type.d.mts +172 -0
- package/esm/prompts/prompts-manager.type.d.mts.map +1 -0
- package/esm/prompts/prompts-validate.mjs +200 -0
- package/esm/prompts/prompts-validate.mjs.map +1 -0
- package/esm/rag/as-tool.mjs +48 -0
- package/esm/rag/as-tool.mjs.map +1 -0
- package/esm/rag/chunk/chunk.d.mts +24 -0
- package/esm/rag/chunk/chunk.d.mts.map +1 -0
- package/esm/rag/chunk/chunk.mjs +44 -0
- package/esm/rag/chunk/chunk.mjs.map +1 -0
- package/esm/rag/chunk/fixed.mjs +32 -0
- package/esm/rag/chunk/fixed.mjs.map +1 -0
- package/esm/rag/chunk/markdown.mjs +75 -0
- package/esm/rag/chunk/markdown.mjs.map +1 -0
- package/esm/rag/chunk/recursive.mjs +132 -0
- package/esm/rag/chunk/recursive.mjs.map +1 -0
- package/esm/rag/chunk/sentence.mjs +73 -0
- package/esm/rag/chunk/sentence.mjs.map +1 -0
- package/esm/rag/contracts/chunk-options.type.d.mts +35 -0
- package/esm/rag/contracts/chunk-options.type.d.mts.map +1 -0
- package/esm/rag/contracts/citation.type.d.mts +35 -0
- package/esm/rag/contracts/citation.type.d.mts.map +1 -0
- package/esm/rag/contracts/index.d.mts +4 -0
- package/esm/rag/contracts/rag-config.type.d.mts +68 -0
- package/esm/rag/contracts/rag-config.type.d.mts.map +1 -0
- package/esm/rag/contracts/rag-document.type.d.mts +21 -0
- package/esm/rag/contracts/rag-document.type.d.mts.map +1 -0
- package/esm/rag/hybrid/bm25.d.mts +23 -0
- package/esm/rag/hybrid/bm25.d.mts.map +1 -0
- package/esm/rag/hybrid/bm25.mjs +51 -0
- package/esm/rag/hybrid/bm25.mjs.map +1 -0
- package/esm/rag/hybrid/hybrid-rank.d.mts +33 -0
- package/esm/rag/hybrid/hybrid-rank.d.mts.map +1 -0
- package/esm/rag/hybrid/hybrid-rank.mjs +29 -0
- package/esm/rag/hybrid/hybrid-rank.mjs.map +1 -0
- package/esm/rag/hybrid/rrf.d.mts +25 -0
- package/esm/rag/hybrid/rrf.d.mts.map +1 -0
- package/esm/rag/hybrid/rrf.mjs +30 -0
- package/esm/rag/hybrid/rrf.mjs.map +1 -0
- package/esm/rag/index.d.mts +22 -0
- package/esm/rag/index.mjs +18 -0
- package/esm/rag/loaders/errors.d.mts +19 -0
- package/esm/rag/loaders/errors.d.mts.map +1 -0
- package/esm/rag/loaders/errors.mjs +25 -0
- package/esm/rag/loaders/errors.mjs.map +1 -0
- package/esm/rag/loaders/index.mjs +7 -0
- package/esm/rag/loaders/load-html.d.mts +26 -0
- package/esm/rag/loaders/load-html.d.mts.map +1 -0
- package/esm/rag/loaders/load-html.mjs +138 -0
- package/esm/rag/loaders/load-html.mjs.map +1 -0
- package/esm/rag/loaders/load-pdf.d.mts +38 -0
- package/esm/rag/loaders/load-pdf.d.mts.map +1 -0
- package/esm/rag/loaders/load-pdf.mjs +150 -0
- package/esm/rag/loaders/load-pdf.mjs.map +1 -0
- package/esm/rag/loaders/load-text.d.mts +47 -0
- package/esm/rag/loaders/load-text.d.mts.map +1 -0
- package/esm/rag/loaders/load-text.mjs +60 -0
- package/esm/rag/loaders/load-text.mjs.map +1 -0
- package/esm/rag/loaders/load-web.d.mts +42 -0
- package/esm/rag/loaders/load-web.d.mts.map +1 -0
- package/esm/rag/loaders/load-web.mjs +89 -0
- package/esm/rag/loaders/load-web.mjs.map +1 -0
- package/esm/rag/loaders/loader.type.d.mts +89 -0
- package/esm/rag/loaders/loader.type.d.mts.map +1 -0
- package/esm/rag/rag.d.mts +38 -0
- package/esm/rag/rag.d.mts.map +1 -0
- package/esm/rag/rag.mjs +126 -0
- package/esm/rag/rag.mjs.map +1 -0
- package/esm/rag/rerank/keyword-reranker.d.mts +32 -0
- package/esm/rag/rerank/keyword-reranker.d.mts.map +1 -0
- package/esm/rag/rerank/keyword-reranker.mjs +58 -0
- package/esm/rag/rerank/keyword-reranker.mjs.map +1 -0
- package/esm/rag/rerank/llm-reranker.d.mts +36 -0
- package/esm/rag/rerank/llm-reranker.d.mts.map +1 -0
- package/esm/rag/rerank/llm-reranker.mjs +85 -0
- package/esm/rag/rerank/llm-reranker.mjs.map +1 -0
- package/esm/rag/rerank/reranker.contract.d.mts +28 -0
- package/esm/rag/rerank/reranker.contract.d.mts.map +1 -0
- package/esm/rag/retrieve.mjs +68 -0
- package/esm/rag/retrieve.mjs.map +1 -0
- package/esm/rag/store/cache-vector-store.d.mts +27 -0
- package/esm/rag/store/cache-vector-store.d.mts.map +1 -0
- package/esm/rag/store/cache-vector-store.mjs +48 -0
- package/esm/rag/store/cache-vector-store.mjs.map +1 -0
- package/esm/rag/store/pg-vector-store.d.mts +139 -0
- package/esm/rag/store/pg-vector-store.d.mts.map +1 -0
- package/esm/rag/store/pg-vector-store.mjs +328 -0
- package/esm/rag/store/pg-vector-store.mjs.map +1 -0
- package/esm/rag/store/vector-store.contract.d.mts +38 -0
- package/esm/rag/store/vector-store.contract.d.mts.map +1 -0
- package/esm/rag/transforms/multi-query.d.mts +27 -0
- package/esm/rag/transforms/multi-query.d.mts.map +1 -0
- package/esm/rag/transforms/multi-query.mjs +41 -0
- package/esm/rag/transforms/multi-query.mjs.map +1 -0
- package/esm/security/index.mjs +5 -0
- package/esm/security/outbound-policy.d.mts +46 -0
- package/esm/security/outbound-policy.d.mts.map +1 -0
- package/esm/security/outbound-policy.mjs +187 -0
- package/esm/security/outbound-policy.mjs.map +1 -0
- package/esm/security/outbound-policy.type.d.mts +74 -0
- package/esm/security/outbound-policy.type.d.mts.map +1 -0
- package/esm/security/private-ip.d.mts +15 -0
- package/esm/security/private-ip.d.mts.map +1 -0
- package/esm/security/private-ip.mjs +48 -0
- package/esm/security/private-ip.mjs.map +1 -0
- package/esm/security/redact.d.mts +59 -0
- package/esm/security/redact.d.mts.map +1 -0
- package/esm/security/redact.mjs +122 -0
- package/esm/security/redact.mjs.map +1 -0
- package/esm/serve/serve.d.mts +50 -0
- package/esm/serve/serve.d.mts.map +1 -0
- package/esm/serve/serve.mjs +90 -0
- package/esm/serve/serve.mjs.map +1 -0
- package/esm/serve/sse.d.mts +20 -0
- package/esm/serve/sse.d.mts.map +1 -0
- package/esm/serve/sse.mjs +25 -0
- package/esm/serve/sse.mjs.map +1 -0
- package/esm/serve/stream-to-sse.d.mts +29 -0
- package/esm/serve/stream-to-sse.d.mts.map +1 -0
- package/esm/serve/stream-to-sse.mjs +37 -0
- package/esm/serve/stream-to-sse.mjs.map +1 -0
- package/esm/skills/catalog.d.mts +49 -0
- package/esm/skills/catalog.d.mts.map +1 -0
- package/esm/skills/catalog.mjs +140 -0
- package/esm/skills/catalog.mjs.map +1 -0
- package/esm/skills/contracts/skill-record.type.d.mts +37 -0
- package/esm/skills/contracts/skill-record.type.d.mts.map +1 -0
- package/esm/skills/contracts/skills-config.type.d.mts +108 -0
- package/esm/skills/contracts/skills-config.type.d.mts.map +1 -0
- package/esm/skills/contracts/skills-store.contract.d.mts +28 -0
- package/esm/skills/contracts/skills-store.contract.d.mts.map +1 -0
- package/esm/skills/contracts/skills.contract.d.mts +43 -0
- package/esm/skills/contracts/skills.contract.d.mts.map +1 -0
- package/esm/skills/index.d.mts +16 -0
- package/esm/skills/index.mjs +14 -0
- package/esm/skills/load-skill-tool.d.mts +38 -0
- package/esm/skills/load-skill-tool.d.mts.map +1 -0
- package/esm/skills/load-skill-tool.mjs +65 -0
- package/esm/skills/load-skill-tool.mjs.map +1 -0
- package/esm/skills/review-gate.d.mts +33 -0
- package/esm/skills/review-gate.d.mts.map +1 -0
- package/esm/skills/review-gate.mjs +60 -0
- package/esm/skills/review-gate.mjs.map +1 -0
- package/esm/skills/save-skill-tool.d.mts +39 -0
- package/esm/skills/save-skill-tool.d.mts.map +1 -0
- package/esm/skills/save-skill-tool.mjs +65 -0
- package/esm/skills/save-skill-tool.mjs.map +1 -0
- package/esm/skills/skills.d.mts +33 -0
- package/esm/skills/skills.d.mts.map +1 -0
- package/esm/skills/skills.mjs +109 -0
- package/esm/skills/skills.mjs.map +1 -0
- package/esm/skills/sources/directory-source.d.mts +19 -0
- package/esm/skills/sources/directory-source.d.mts.map +1 -0
- package/esm/skills/sources/directory-source.mjs +108 -0
- package/esm/skills/sources/directory-source.mjs.map +1 -0
- package/esm/skills/sources/index.d.mts +18 -0
- package/esm/skills/sources/index.d.mts.map +1 -0
- package/esm/skills/sources/index.mjs +27 -0
- package/esm/skills/sources/index.mjs.map +1 -0
- package/esm/skills/sources/parse-frontmatter.d.mts +27 -0
- package/esm/skills/sources/parse-frontmatter.d.mts.map +1 -0
- package/esm/skills/sources/parse-frontmatter.mjs +46 -0
- package/esm/skills/sources/parse-frontmatter.mjs.map +1 -0
- package/esm/skills/sources/store-source.d.mts +14 -0
- package/esm/skills/sources/store-source.d.mts.map +1 -0
- package/esm/skills/sources/store-source.mjs +15 -0
- package/esm/skills/sources/store-source.mjs.map +1 -0
- package/esm/skills/sources/url-source.d.mts +29 -0
- package/esm/skills/sources/url-source.d.mts.map +1 -0
- package/esm/skills/sources/url-source.mjs +117 -0
- package/esm/skills/sources/url-source.mjs.map +1 -0
- package/esm/skills/store/mock-skills-store.d.mts +57 -0
- package/esm/skills/store/mock-skills-store.d.mts.map +1 -0
- package/esm/skills/store/mock-skills-store.mjs +100 -0
- package/esm/skills/store/mock-skills-store.mjs.map +1 -0
- package/esm/skills/store/procedural-skill-store.d.mts +30 -0
- package/esm/skills/store/procedural-skill-store.d.mts.map +1 -0
- package/esm/skills/store/procedural-skill-store.mjs +125 -0
- package/esm/skills/store/procedural-skill-store.mjs.map +1 -0
- package/esm/speech/index.mjs +3 -0
- package/esm/speech/speech.d.mts +65 -0
- package/esm/speech/speech.d.mts.map +1 -0
- package/esm/speech/speech.mjs +123 -0
- package/esm/speech/speech.mjs.map +1 -0
- package/esm/supervisor/as-tool.mjs +2 -2
- package/esm/supervisor/as-tool.mjs.map +1 -1
- package/esm/supervisor/entries.mjs +2 -2
- package/esm/supervisor/entries.mjs.map +1 -1
- package/esm/supervisor/execution.d.mts.map +1 -1
- package/esm/supervisor/execution.mjs +31 -28
- package/esm/supervisor/execution.mjs.map +1 -1
- package/esm/supervisor/supervisor.d.mts.map +1 -1
- package/esm/supervisor/supervisor.mjs +8 -3
- package/esm/supervisor/supervisor.mjs.map +1 -1
- package/esm/system-prompt/index.d.mts +4 -0
- package/esm/system-prompt/system-prompt.d.mts +68 -4
- package/esm/system-prompt/system-prompt.d.mts.map +1 -1
- package/esm/system-prompt/system-prompt.mjs +89 -5
- package/esm/system-prompt/system-prompt.mjs.map +1 -1
- package/esm/team/gates.mjs +48 -0
- package/esm/team/gates.mjs.map +1 -0
- package/esm/team/index.d.mts +1 -0
- package/esm/team/index.mjs +3 -0
- package/esm/team/team.d.mts +42 -0
- package/esm/team/team.d.mts.map +1 -0
- package/esm/team/team.mjs +94 -0
- package/esm/team/team.mjs.map +1 -0
- package/esm/tool/executable-as-tool.d.mts.map +1 -1
- package/esm/tool/executable-as-tool.mjs +2 -2
- package/esm/tool/executable-as-tool.mjs.map +1 -1
- package/esm/tool/tool.d.mts.map +1 -1
- package/esm/tool/tool.mjs +2 -2
- package/esm/tool/tool.mjs.map +1 -1
- package/esm/transcribe/audio-input.d.mts +47 -0
- package/esm/transcribe/audio-input.d.mts.map +1 -0
- package/esm/transcribe/audio-input.mjs +84 -0
- package/esm/transcribe/audio-input.mjs.map +1 -0
- package/esm/transcribe/index.mjs +4 -0
- package/esm/transcribe/transcribe.d.mts +64 -0
- package/esm/transcribe/transcribe.d.mts.map +1 -0
- package/esm/transcribe/transcribe.mjs +128 -0
- package/esm/transcribe/transcribe.mjs.map +1 -0
- package/esm/utils/compute-cost.d.mts +17 -1
- package/esm/utils/compute-cost.d.mts.map +1 -1
- package/esm/utils/compute-cost.mjs +26 -1
- package/esm/utils/compute-cost.mjs.map +1 -1
- package/esm/utils/extract-json-lenient.d.mts +42 -0
- package/esm/utils/extract-json-lenient.d.mts.map +1 -0
- package/esm/utils/extract-json-lenient.mjs +97 -0
- package/esm/utils/extract-json-lenient.mjs.map +1 -0
- package/esm/utils/index.d.mts +4 -2
- package/esm/utils/index.mjs +3 -1
- package/esm/utils/json-schema.d.mts +1 -1
- package/esm/utils/prepare-attachment-part.d.mts +10 -1
- package/esm/utils/prepare-attachment-part.d.mts.map +1 -1
- package/esm/utils/prepare-attachment-part.mjs +103 -11
- package/esm/utils/prepare-attachment-part.mjs.map +1 -1
- package/esm/utils/resolve-attachment.d.mts +4 -3
- package/esm/utils/resolve-attachment.d.mts.map +1 -1
- package/esm/utils/resolve-attachment.mjs +4 -3
- package/esm/utils/resolve-attachment.mjs.map +1 -1
- package/esm/utils/run-context.d.mts +94 -0
- package/esm/utils/run-context.d.mts.map +1 -0
- package/esm/utils/run-context.mjs +98 -0
- package/esm/utils/run-context.mjs.map +1 -0
- package/esm/vcr/cassette-io.mjs +57 -0
- package/esm/vcr/cassette-io.mjs.map +1 -0
- package/esm/vcr/errors.d.mts +42 -0
- package/esm/vcr/errors.d.mts.map +1 -0
- package/esm/vcr/errors.mjs +37 -0
- package/esm/vcr/errors.mjs.map +1 -0
- package/esm/vcr/hash-request.d.mts +28 -0
- package/esm/vcr/hash-request.d.mts.map +1 -0
- package/esm/vcr/hash-request.mjs +118 -0
- package/esm/vcr/hash-request.mjs.map +1 -0
- package/esm/vcr/index.d.mts +4 -0
- package/esm/vcr/index.mjs +5 -0
- package/esm/vcr/vcr.d.mts +32 -0
- package/esm/vcr/vcr.d.mts.map +1 -0
- package/esm/vcr/vcr.mjs +248 -0
- package/esm/vcr/vcr.mjs.map +1 -0
- package/esm/vcr/vcr.type.d.mts +118 -0
- package/esm/vcr/vcr.type.d.mts.map +1 -0
- package/esm/workflow/as-tool.mjs +2 -2
- package/esm/workflow/as-tool.mjs.map +1 -1
- package/esm/workflow/engine.mjs +1 -0
- package/esm/workflow/engine.mjs.map +1 -1
- package/esm/workflow/step-runner.mjs +19 -20
- package/esm/workflow/step-runner.mjs.map +1 -1
- package/esm/workflow/workflow.d.mts.map +1 -1
- package/esm/workflow/workflow.mjs +8 -3
- package/esm/workflow/workflow.mjs.map +1 -1
- package/llms-full.txt +2572 -204
- package/llms.txt +21 -4
- package/package.json +7 -3
- package/skills/README.md +44 -4
- package/skills/ai-dx-helpers/SKILL.md +2 -2
- package/skills/approve-tool-calls/SKILL.md +134 -0
- package/skills/attach-ai-middleware/SKILL.md +1 -1
- package/skills/detect-and-redact-pii/SKILL.md +104 -0
- package/skills/durable-agent-runs/SKILL.md +135 -0
- package/skills/durable-resume/SKILL.md +128 -0
- package/skills/escalate-block-to-human/SKILL.md +85 -0
- package/skills/eval-datasets-and-ci/SKILL.md +117 -0
- package/skills/generate-images/SKILL.md +138 -0
- package/skills/generate-speech/SKILL.md +139 -0
- package/skills/guard-input-output/SKILL.md +117 -0
- package/skills/manage-prompts/SKILL.md +186 -0
- package/skills/observe-ai-flows/SKILL.md +94 -0
- package/skills/rag-loaders-and-stores/SKILL.md +164 -0
- package/skills/record-replay-llm/SKILL.md +92 -0
- package/skills/run-ai-agent/SKILL.md +26 -1
- package/skills/run-ai-rag/SKILL.md +139 -0
- package/skills/run-ai-team/SKILL.md +107 -0
- package/skills/run-orchestrator/SKILL.md +2 -0
- package/skills/run-planner/SKILL.md +73 -8
- package/skills/run-supervisor/SKILL.md +20 -1
- package/skills/transcribe-audio/SKILL.md +157 -0
- package/skills/use-runtime-skills/SKILL.md +106 -0
- package/skills/write-system-prompt/SKILL.md +30 -1
- package/cjs/index.cjs.map +0 -1
- package/esm/contracts/result/index.d.mts +0 -15
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ModelContract } from "../../contracts/model.contract.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/rag/transforms/multi-query.d.ts
|
|
4
|
+
/** Options for {@link multiQuery}. */
|
|
5
|
+
type MultiQueryOptions = {
|
|
6
|
+
/** How many alternative phrasings to request. Default 3. */n?: number; /** Include the original query in the returned list. Default true. */
|
|
7
|
+
includeOriginal?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Multi-query expansion (A4) — ask a model for several alternative
|
|
11
|
+
* phrasings of `query`, so retrieval covers vocabulary the original
|
|
12
|
+
* wording missed (synonyms, specificity, rephrasings). Pair the variants
|
|
13
|
+
* with {@link hybridRank} / a vector search and fuse the per-variant hits.
|
|
14
|
+
*
|
|
15
|
+
* Deterministic, dependency-light parsing: the model is asked for one
|
|
16
|
+
* query per line; bullets / numbering are stripped, blanks dropped, and
|
|
17
|
+
* the set is de-duplicated. Returns the original (unless opted out) plus
|
|
18
|
+
* up to `n` variants.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const queries = await multiQuery(model, "how do I cancel?", { n: 3 });
|
|
22
|
+
* // → ["how do I cancel?", "cancel my subscription", "end my plan", ...]
|
|
23
|
+
*/
|
|
24
|
+
declare function multiQuery(model: ModelContract, query: string, options?: MultiQueryOptions): Promise<string[]>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { MultiQueryOptions, multiQuery };
|
|
27
|
+
//# sourceMappingURL=multi-query.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-query.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/rag/transforms/multi-query.ts"],"mappings":";;;;KAGY,iBAAA;EAAA,4DAEV,CAAA;EAEA,eAAe;AAAA;AAkBjB;;;;;;;;;;;;;;;AAAA,iBAAsB,UAAA,CACpB,KAAA,EAAO,aAAA,EACP,KAAA,UACA,OAAA,GAAS,iBAAA,GACR,OAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/rag/transforms/multi-query.ts
|
|
2
|
+
/**
|
|
3
|
+
* Multi-query expansion (A4) — ask a model for several alternative
|
|
4
|
+
* phrasings of `query`, so retrieval covers vocabulary the original
|
|
5
|
+
* wording missed (synonyms, specificity, rephrasings). Pair the variants
|
|
6
|
+
* with {@link hybridRank} / a vector search and fuse the per-variant hits.
|
|
7
|
+
*
|
|
8
|
+
* Deterministic, dependency-light parsing: the model is asked for one
|
|
9
|
+
* query per line; bullets / numbering are stripped, blanks dropped, and
|
|
10
|
+
* the set is de-duplicated. Returns the original (unless opted out) plus
|
|
11
|
+
* up to `n` variants.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const queries = await multiQuery(model, "how do I cancel?", { n: 3 });
|
|
15
|
+
* // → ["how do I cancel?", "cancel my subscription", "end my plan", ...]
|
|
16
|
+
*/
|
|
17
|
+
async function multiQuery(model, query, options = {}) {
|
|
18
|
+
const n = options.n ?? 3;
|
|
19
|
+
const includeOriginal = options.includeOriginal ?? true;
|
|
20
|
+
const prompt = `Rewrite the following search query into ${n} alternative phrasings that would retrieve relevant documents. Output ONE query per line, no numbering or commentary.\n\nQuery: ${query}`;
|
|
21
|
+
const variants = (await model.complete([{
|
|
22
|
+
role: "user",
|
|
23
|
+
content: prompt
|
|
24
|
+
}])).content.split("\n").map((line) => line.replace(/^\s*(?:[-*•]|\d+[.)])\s*/, "").trim()).filter(Boolean);
|
|
25
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26
|
+
const out = [];
|
|
27
|
+
const add = (q) => {
|
|
28
|
+
const key = q.toLowerCase();
|
|
29
|
+
if (!seen.has(key)) {
|
|
30
|
+
seen.add(key);
|
|
31
|
+
out.push(q);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
if (includeOriginal) add(query);
|
|
35
|
+
for (const variant of variants.slice(0, n)) add(variant);
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { multiQuery };
|
|
41
|
+
//# sourceMappingURL=multi-query.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-query.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/rag/transforms/multi-query.ts"],"sourcesContent":["import type { ModelContract } from \"../../contracts/model.contract\";\n\n/** Options for {@link multiQuery}. */\nexport type MultiQueryOptions = {\n /** How many alternative phrasings to request. Default 3. */\n n?: number;\n /** Include the original query in the returned list. Default true. */\n includeOriginal?: boolean;\n};\n\n/**\n * Multi-query expansion (A4) — ask a model for several alternative\n * phrasings of `query`, so retrieval covers vocabulary the original\n * wording missed (synonyms, specificity, rephrasings). Pair the variants\n * with {@link hybridRank} / a vector search and fuse the per-variant hits.\n *\n * Deterministic, dependency-light parsing: the model is asked for one\n * query per line; bullets / numbering are stripped, blanks dropped, and\n * the set is de-duplicated. Returns the original (unless opted out) plus\n * up to `n` variants.\n *\n * @example\n * const queries = await multiQuery(model, \"how do I cancel?\", { n: 3 });\n * // → [\"how do I cancel?\", \"cancel my subscription\", \"end my plan\", ...]\n */\nexport async function multiQuery(\n model: ModelContract,\n query: string,\n options: MultiQueryOptions = {},\n): Promise<string[]> {\n const n = options.n ?? 3;\n const includeOriginal = options.includeOriginal ?? true;\n\n const prompt =\n `Rewrite the following search query into ${n} alternative phrasings that would ` +\n `retrieve relevant documents. Output ONE query per line, no numbering or commentary.\\n\\n` +\n `Query: ${query}`;\n\n const response = await model.complete([{ role: \"user\", content: prompt }]);\n\n const variants = response.content\n .split(\"\\n\")\n .map(line => line.replace(/^\\s*(?:[-*•]|\\d+[.)])\\s*/, \"\").trim())\n .filter(Boolean);\n\n const seen = new Set<string>();\n const out: string[] = [];\n\n const add = (q: string) => {\n const key = q.toLowerCase();\n if (!seen.has(key)) {\n seen.add(key);\n out.push(q);\n }\n };\n\n if (includeOriginal) add(query);\n for (const variant of variants.slice(0, n)) add(variant);\n\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,eAAsB,WACpB,OACA,OACA,UAA6B,CAAC,GACX;CACnB,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,kBAAkB,QAAQ,mBAAmB;CAEnD,MAAM,SACJ,2CAA2C,EAAE,kIAEnC;CAIZ,MAAM,YAAW,MAFM,MAAM,SAAS,CAAC;EAAE,MAAM;EAAQ,SAAS;CAAO,CAAC,CAAC,EAEhD,CAAC,QACvB,MAAM,IAAI,CAAC,CACX,KAAI,SAAQ,KAAK,QAAQ,4BAA4B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAChE,OAAO,OAAO;CAEjB,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAgB,CAAC;CAEvB,MAAM,OAAO,MAAc;EACzB,MAAM,MAAM,EAAE,YAAY;EAC1B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,KAAK,IAAI,GAAG;GACZ,IAAI,KAAK,CAAC;EACZ;CACF;CAEA,IAAI,iBAAiB,IAAI,KAAK;CAC9B,KAAK,MAAM,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG,IAAI,OAAO;CAEvD,OAAO;AACT"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { isPrivateOrReservedIp } from "./private-ip.mjs";
|
|
2
|
+
import { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy } from "./outbound-policy.mjs";
|
|
3
|
+
import { DEFAULT_SENSITIVE_KEYS, SENSITIVE_HEADERS, redact, redactError, redactHeaders, scrubSecrets } from "./redact.mjs";
|
|
4
|
+
|
|
5
|
+
export { };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { OutboundPolicy, ResolvedOutboundPolicy } from "./outbound-policy.type.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/security/outbound-policy.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Fill an {@link OutboundPolicy} with strict defaults: https-only,
|
|
6
|
+
* private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent
|
|
7
|
+
* — resolving an already-resolved policy yields the same shape.
|
|
8
|
+
*/
|
|
9
|
+
declare function resolveOutboundPolicy(policy?: OutboundPolicy): ResolvedOutboundPolicy;
|
|
10
|
+
/**
|
|
11
|
+
* Validate a URL against the policy BEFORE any network call: scheme
|
|
12
|
+
* allowlist, host allowlist, and (when enabled) a DNS resolution that
|
|
13
|
+
* rejects private / loopback / link-local / metadata addresses — the SSRF
|
|
14
|
+
* guard. Returns the parsed `URL` on success; throws
|
|
15
|
+
* {@link OutboundPolicyError} otherwise.
|
|
16
|
+
*/
|
|
17
|
+
declare function assertUrlAllowed(rawUrl: string, policy: ResolvedOutboundPolicy): Promise<URL>;
|
|
18
|
+
/**
|
|
19
|
+
* Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),
|
|
20
|
+
* then performs the request with the policy's timeout and (optional)
|
|
21
|
+
* caller signal merged. Returns the raw `Response` — read its body via
|
|
22
|
+
* {@link readTextCapped} to enforce `maxBytes`. Throws
|
|
23
|
+
* {@link OutboundPolicyError} on a policy violation or timeout.
|
|
24
|
+
*/
|
|
25
|
+
declare function guardedFetch(rawUrl: string, policyInput: OutboundPolicy, init?: RequestInit): Promise<Response>;
|
|
26
|
+
/**
|
|
27
|
+
* Read a response body as UTF-8 text with a hard byte cap. A declared
|
|
28
|
+
* `content-length` over the cap fails fast; otherwise the stream is read
|
|
29
|
+
* chunk-by-chunk and aborted the moment the running total exceeds
|
|
30
|
+
* `maxBytes`. Throws {@link OutboundPolicyError} on overflow.
|
|
31
|
+
*/
|
|
32
|
+
declare function readTextCapped(response: Response, maxBytes: number): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the
|
|
35
|
+
* response status alongside the (capped) body text so callers can shape
|
|
36
|
+
* their own not-OK error. The body is only read when the response is OK.
|
|
37
|
+
*/
|
|
38
|
+
declare function fetchTextWithPolicy(rawUrl: string, policyInput: OutboundPolicy, init?: RequestInit): Promise<{
|
|
39
|
+
ok: boolean;
|
|
40
|
+
status: number;
|
|
41
|
+
statusText: string;
|
|
42
|
+
text: string;
|
|
43
|
+
}>;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy };
|
|
46
|
+
//# sourceMappingURL=outbound-policy.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-policy.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/outbound-policy.ts"],"mappings":";;;;;AAmBA;;;iBAAgB,qBAAA,CACd,MAAA,GAAQ,cAAA,GACP,sBAAsB;;;;;AAAA;AAiCzB;;iBAAsB,gBAAA,CACpB,MAAA,UACA,MAAA,EAAQ,sBAAA,GACP,OAAA,CAAQ,GAAA;;;;;;;;iBAiGW,YAAA,CACpB,MAAA,UACA,WAAA,EAAa,cAAA,EACb,IAAA,GAAO,WAAA,GACN,OAAA,CAAQ,QAAA;;;;AArGG;AAiGd;;iBAkCsB,cAAA,CACpB,QAAA,EAAU,QAAA,EACV,QAAA,WACC,OAAO;;;;;;iBAgDY,mBAAA,CACpB,MAAA,UACA,WAAA,EAAa,cAAA,EACb,IAAA,GAAO,WAAA,GACN,OAAA;EAAU,EAAA;EAAa,MAAA;EAAgB,UAAA;EAAoB,IAAA;AAAA"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { OutboundPolicyError } from "../errors/outbound-policy-error.mjs";
|
|
2
|
+
import "../errors/index.mjs";
|
|
3
|
+
import { isPrivateOrReservedIp } from "./private-ip.mjs";
|
|
4
|
+
import { lookup } from "node:dns/promises";
|
|
5
|
+
import { isIP } from "node:net";
|
|
6
|
+
|
|
7
|
+
//#region ../@warlock.js/ai/src/security/outbound-policy.ts
|
|
8
|
+
/** 5 MiB — default cap on an outbound response body. */
|
|
9
|
+
const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
|
|
10
|
+
/** 10s — default per-request timeout. */
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
12
|
+
/**
|
|
13
|
+
* Fill an {@link OutboundPolicy} with strict defaults: https-only,
|
|
14
|
+
* private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent
|
|
15
|
+
* — resolving an already-resolved policy yields the same shape.
|
|
16
|
+
*/
|
|
17
|
+
function resolveOutboundPolicy(policy = {}) {
|
|
18
|
+
return {
|
|
19
|
+
allowedSchemes: policy.allowedSchemes ?? ["https"],
|
|
20
|
+
hostAllowlist: policy.hostAllowlist,
|
|
21
|
+
denyPrivateIPsAfterDNS: policy.denyPrivateIPsAfterDNS ?? true,
|
|
22
|
+
maxBytes: policy.maxBytes ?? DEFAULT_MAX_BYTES,
|
|
23
|
+
timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
24
|
+
signal: policy.signal,
|
|
25
|
+
fetch: policy.fetch ?? globalThis.fetch
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Strip the `[ ]` IPv6 brackets `URL.hostname` keeps. */
|
|
29
|
+
function stripBrackets(host) {
|
|
30
|
+
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
31
|
+
}
|
|
32
|
+
/** Whether `host` equals or is a subdomain of any allowlist entry. */
|
|
33
|
+
function hostAllowed(host, allowlist) {
|
|
34
|
+
const lower = host.toLowerCase();
|
|
35
|
+
return allowlist.some((entry) => {
|
|
36
|
+
const e = entry.toLowerCase();
|
|
37
|
+
return lower === e || lower.endsWith(`.${e}`);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validate a URL against the policy BEFORE any network call: scheme
|
|
42
|
+
* allowlist, host allowlist, and (when enabled) a DNS resolution that
|
|
43
|
+
* rejects private / loopback / link-local / metadata addresses — the SSRF
|
|
44
|
+
* guard. Returns the parsed `URL` on success; throws
|
|
45
|
+
* {@link OutboundPolicyError} otherwise.
|
|
46
|
+
*/
|
|
47
|
+
async function assertUrlAllowed(rawUrl, policy) {
|
|
48
|
+
let url;
|
|
49
|
+
try {
|
|
50
|
+
url = new URL(rawUrl);
|
|
51
|
+
} catch {
|
|
52
|
+
throw new OutboundPolicyError(`outbound request blocked — invalid URL: ${rawUrl}`, { context: { url: rawUrl } });
|
|
53
|
+
}
|
|
54
|
+
const scheme = url.protocol.replace(/:$/, "").toLowerCase();
|
|
55
|
+
if (!policy.allowedSchemes.some((s) => s.toLowerCase() === scheme)) throw new OutboundPolicyError(`outbound request blocked — scheme "${scheme}" is not allowed (allowed: ${policy.allowedSchemes.join(", ")})`, { context: {
|
|
56
|
+
url: rawUrl,
|
|
57
|
+
scheme
|
|
58
|
+
} });
|
|
59
|
+
const host = stripBrackets(url.hostname);
|
|
60
|
+
if (policy.hostAllowlist && !hostAllowed(host, policy.hostAllowlist)) throw new OutboundPolicyError(`outbound request blocked — host "${host}" is not in the allowlist`, { context: {
|
|
61
|
+
url: rawUrl,
|
|
62
|
+
host
|
|
63
|
+
} });
|
|
64
|
+
if (policy.denyPrivateIPsAfterDNS) await assertHostNotPrivate(host, rawUrl);
|
|
65
|
+
return url;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reject when `host` is — or resolves to — a private / reserved address.
|
|
69
|
+
* IP literals are checked directly; hostnames are resolved via DNS and
|
|
70
|
+
* every returned address is checked (a public name pointing inward is
|
|
71
|
+
* caught). A resolution failure fails closed.
|
|
72
|
+
*/
|
|
73
|
+
async function assertHostNotPrivate(host, rawUrl) {
|
|
74
|
+
if (isIP(host) !== 0) {
|
|
75
|
+
if (isPrivateOrReservedIp(host)) throw new OutboundPolicyError(`outbound request blocked — "${host}" is a private/reserved address`, { context: {
|
|
76
|
+
url: rawUrl,
|
|
77
|
+
address: host
|
|
78
|
+
} });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let addresses;
|
|
82
|
+
try {
|
|
83
|
+
addresses = await lookup(host, { all: true });
|
|
84
|
+
} catch (cause) {
|
|
85
|
+
throw new OutboundPolicyError(`outbound request blocked — could not resolve host "${host}" to verify it is public`, {
|
|
86
|
+
cause,
|
|
87
|
+
context: {
|
|
88
|
+
url: rawUrl,
|
|
89
|
+
host
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
for (const { address } of addresses) if (isPrivateOrReservedIp(address)) throw new OutboundPolicyError(`outbound request blocked — host "${host}" resolves to a private/reserved address (${address})`, { context: {
|
|
94
|
+
url: rawUrl,
|
|
95
|
+
host,
|
|
96
|
+
address
|
|
97
|
+
} });
|
|
98
|
+
}
|
|
99
|
+
/** Merge the internal timeout signal with an optional caller signal. */
|
|
100
|
+
function mergeSignals(timeout, external) {
|
|
101
|
+
if (!external) return timeout;
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
const abort = (from) => controller.abort(from.reason);
|
|
104
|
+
if (timeout.aborted) abort(timeout);
|
|
105
|
+
else timeout.addEventListener("abort", () => abort(timeout), { once: true });
|
|
106
|
+
if (external.aborted) abort(external);
|
|
107
|
+
else external.addEventListener("abort", () => abort(external), { once: true });
|
|
108
|
+
return controller.signal;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),
|
|
112
|
+
* then performs the request with the policy's timeout and (optional)
|
|
113
|
+
* caller signal merged. Returns the raw `Response` — read its body via
|
|
114
|
+
* {@link readTextCapped} to enforce `maxBytes`. Throws
|
|
115
|
+
* {@link OutboundPolicyError} on a policy violation or timeout.
|
|
116
|
+
*/
|
|
117
|
+
async function guardedFetch(rawUrl, policyInput, init) {
|
|
118
|
+
const policy = resolveOutboundPolicy(policyInput);
|
|
119
|
+
const url = await assertUrlAllowed(rawUrl, policy);
|
|
120
|
+
const timeoutController = new AbortController();
|
|
121
|
+
const timer = setTimeout(() => {
|
|
122
|
+
timeoutController.abort(new OutboundPolicyError(`outbound request timed out after ${policy.timeoutMs}ms`, { context: {
|
|
123
|
+
url: rawUrl,
|
|
124
|
+
timeoutMs: policy.timeoutMs
|
|
125
|
+
} }));
|
|
126
|
+
}, policy.timeoutMs);
|
|
127
|
+
try {
|
|
128
|
+
return await policy.fetch(url, {
|
|
129
|
+
...init,
|
|
130
|
+
signal: mergeSignals(timeoutController.signal, policy.signal)
|
|
131
|
+
});
|
|
132
|
+
} finally {
|
|
133
|
+
clearTimeout(timer);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Read a response body as UTF-8 text with a hard byte cap. A declared
|
|
138
|
+
* `content-length` over the cap fails fast; otherwise the stream is read
|
|
139
|
+
* chunk-by-chunk and aborted the moment the running total exceeds
|
|
140
|
+
* `maxBytes`. Throws {@link OutboundPolicyError} on overflow.
|
|
141
|
+
*/
|
|
142
|
+
async function readTextCapped(response, maxBytes) {
|
|
143
|
+
const declared = Number(response.headers.get("content-length"));
|
|
144
|
+
if (Number.isFinite(declared) && declared > maxBytes) throw new OutboundPolicyError(`outbound response body too large — declared ${declared} bytes exceeds the ${maxBytes}-byte cap`, { context: {
|
|
145
|
+
declared,
|
|
146
|
+
maxBytes
|
|
147
|
+
} });
|
|
148
|
+
if (!response.body) {
|
|
149
|
+
const text = await response.text();
|
|
150
|
+
if (Buffer.byteLength(text) > maxBytes) throw new OutboundPolicyError(`outbound response body exceeded the ${maxBytes}-byte cap`, { context: { maxBytes } });
|
|
151
|
+
return text;
|
|
152
|
+
}
|
|
153
|
+
const reader = response.body.getReader();
|
|
154
|
+
const chunks = [];
|
|
155
|
+
let total = 0;
|
|
156
|
+
for (;;) {
|
|
157
|
+
const { done, value } = await reader.read();
|
|
158
|
+
if (done) break;
|
|
159
|
+
if (!value) continue;
|
|
160
|
+
total += value.byteLength;
|
|
161
|
+
if (total > maxBytes) {
|
|
162
|
+
await reader.cancel();
|
|
163
|
+
throw new OutboundPolicyError(`outbound response body exceeded the ${maxBytes}-byte cap`, { context: { maxBytes } });
|
|
164
|
+
}
|
|
165
|
+
chunks.push(value);
|
|
166
|
+
}
|
|
167
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the
|
|
171
|
+
* response status alongside the (capped) body text so callers can shape
|
|
172
|
+
* their own not-OK error. The body is only read when the response is OK.
|
|
173
|
+
*/
|
|
174
|
+
async function fetchTextWithPolicy(rawUrl, policyInput, init) {
|
|
175
|
+
const policy = resolveOutboundPolicy(policyInput);
|
|
176
|
+
const response = await guardedFetch(rawUrl, policy, init);
|
|
177
|
+
return {
|
|
178
|
+
ok: response.ok,
|
|
179
|
+
status: response.status,
|
|
180
|
+
statusText: response.statusText,
|
|
181
|
+
text: response.ok ? await readTextCapped(response, policy.maxBytes) : ""
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
export { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy };
|
|
187
|
+
//# sourceMappingURL=outbound-policy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-policy.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/outbound-policy.ts"],"sourcesContent":["import { lookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\nimport { OutboundPolicyError } from \"../errors\";\nimport { isPrivateOrReservedIp } from \"./private-ip\";\nimport type {\n OutboundPolicy,\n ResolvedOutboundPolicy,\n} from \"./outbound-policy.type\";\n\n/** 5 MiB — default cap on an outbound response body. */\nconst DEFAULT_MAX_BYTES = 5 * 1024 * 1024;\n/** 10s — default per-request timeout. */\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * Fill an {@link OutboundPolicy} with strict defaults: https-only,\n * private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent\n * — resolving an already-resolved policy yields the same shape.\n */\nexport function resolveOutboundPolicy(\n policy: OutboundPolicy = {},\n): ResolvedOutboundPolicy {\n return {\n allowedSchemes: policy.allowedSchemes ?? [\"https\"],\n hostAllowlist: policy.hostAllowlist,\n denyPrivateIPsAfterDNS: policy.denyPrivateIPsAfterDNS ?? true,\n maxBytes: policy.maxBytes ?? DEFAULT_MAX_BYTES,\n timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: policy.signal,\n fetch: policy.fetch ?? globalThis.fetch,\n };\n}\n\n/** Strip the `[ ]` IPv6 brackets `URL.hostname` keeps. */\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n\n/** Whether `host` equals or is a subdomain of any allowlist entry. */\nfunction hostAllowed(host: string, allowlist: string[]): boolean {\n const lower = host.toLowerCase();\n return allowlist.some(entry => {\n const e = entry.toLowerCase();\n return lower === e || lower.endsWith(`.${e}`);\n });\n}\n\n/**\n * Validate a URL against the policy BEFORE any network call: scheme\n * allowlist, host allowlist, and (when enabled) a DNS resolution that\n * rejects private / loopback / link-local / metadata addresses — the SSRF\n * guard. Returns the parsed `URL` on success; throws\n * {@link OutboundPolicyError} otherwise.\n */\nexport async function assertUrlAllowed(\n rawUrl: string,\n policy: ResolvedOutboundPolicy,\n): Promise<URL> {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new OutboundPolicyError(`outbound request blocked — invalid URL: ${rawUrl}`, {\n context: { url: rawUrl },\n });\n }\n\n const scheme = url.protocol.replace(/:$/, \"\").toLowerCase();\n if (!policy.allowedSchemes.some(s => s.toLowerCase() === scheme)) {\n throw new OutboundPolicyError(\n `outbound request blocked — scheme \"${scheme}\" is not allowed (allowed: ${policy.allowedSchemes.join(\", \")})`,\n { context: { url: rawUrl, scheme } },\n );\n }\n\n const host = stripBrackets(url.hostname);\n\n if (policy.hostAllowlist && !hostAllowed(host, policy.hostAllowlist)) {\n throw new OutboundPolicyError(\n `outbound request blocked — host \"${host}\" is not in the allowlist`,\n { context: { url: rawUrl, host } },\n );\n }\n\n if (policy.denyPrivateIPsAfterDNS) {\n await assertHostNotPrivate(host, rawUrl);\n }\n\n return url;\n}\n\n/**\n * Reject when `host` is — or resolves to — a private / reserved address.\n * IP literals are checked directly; hostnames are resolved via DNS and\n * every returned address is checked (a public name pointing inward is\n * caught). A resolution failure fails closed.\n */\nasync function assertHostNotPrivate(host: string, rawUrl: string): Promise<void> {\n if (isIP(host) !== 0) {\n if (isPrivateOrReservedIp(host)) {\n throw new OutboundPolicyError(\n `outbound request blocked — \"${host}\" is a private/reserved address`,\n { context: { url: rawUrl, address: host } },\n );\n }\n return;\n }\n\n let addresses: Array<{ address: string }>;\n try {\n addresses = await lookup(host, { all: true });\n } catch (cause) {\n throw new OutboundPolicyError(\n `outbound request blocked — could not resolve host \"${host}\" to verify it is public`,\n { cause, context: { url: rawUrl, host } },\n );\n }\n\n for (const { address } of addresses) {\n if (isPrivateOrReservedIp(address)) {\n throw new OutboundPolicyError(\n `outbound request blocked — host \"${host}\" resolves to a private/reserved address (${address})`,\n { context: { url: rawUrl, host, address } },\n );\n }\n }\n}\n\n/** Merge the internal timeout signal with an optional caller signal. */\nfunction mergeSignals(\n timeout: AbortSignal,\n external?: AbortSignal,\n): AbortSignal {\n if (!external) return timeout;\n\n const controller = new AbortController();\n const abort = (from: AbortSignal) => controller.abort(from.reason);\n\n if (timeout.aborted) abort(timeout);\n else timeout.addEventListener(\"abort\", () => abort(timeout), { once: true });\n\n if (external.aborted) abort(external);\n else external.addEventListener(\"abort\", () => abort(external), { once: true });\n\n return controller.signal;\n}\n\n/**\n * Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),\n * then performs the request with the policy's timeout and (optional)\n * caller signal merged. Returns the raw `Response` — read its body via\n * {@link readTextCapped} to enforce `maxBytes`. Throws\n * {@link OutboundPolicyError} on a policy violation or timeout.\n */\nexport async function guardedFetch(\n rawUrl: string,\n policyInput: OutboundPolicy,\n init?: RequestInit,\n): Promise<Response> {\n const policy = resolveOutboundPolicy(policyInput);\n const url = await assertUrlAllowed(rawUrl, policy);\n\n const timeoutController = new AbortController();\n const timer = setTimeout(() => {\n timeoutController.abort(\n new OutboundPolicyError(\n `outbound request timed out after ${policy.timeoutMs}ms`,\n { context: { url: rawUrl, timeoutMs: policy.timeoutMs } },\n ),\n );\n }, policy.timeoutMs);\n\n try {\n return await policy.fetch(url, {\n ...init,\n signal: mergeSignals(timeoutController.signal, policy.signal),\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Read a response body as UTF-8 text with a hard byte cap. A declared\n * `content-length` over the cap fails fast; otherwise the stream is read\n * chunk-by-chunk and aborted the moment the running total exceeds\n * `maxBytes`. Throws {@link OutboundPolicyError} on overflow.\n */\nexport async function readTextCapped(\n response: Response,\n maxBytes: number,\n): Promise<string> {\n const declared = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(declared) && declared > maxBytes) {\n throw new OutboundPolicyError(\n `outbound response body too large — declared ${declared} bytes exceeds the ${maxBytes}-byte cap`,\n { context: { declared, maxBytes } },\n );\n }\n\n if (!response.body) {\n const text = await response.text();\n if (Buffer.byteLength(text) > maxBytes) {\n throw new OutboundPolicyError(\n `outbound response body exceeded the ${maxBytes}-byte cap`,\n { context: { maxBytes } },\n );\n }\n return text;\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n throw new OutboundPolicyError(\n `outbound response body exceeded the ${maxBytes}-byte cap`,\n { context: { maxBytes } },\n );\n }\n chunks.push(value);\n }\n\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/**\n * Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the\n * response status alongside the (capped) body text so callers can shape\n * their own not-OK error. The body is only read when the response is OK.\n */\nexport async function fetchTextWithPolicy(\n rawUrl: string,\n policyInput: OutboundPolicy,\n init?: RequestInit,\n): Promise<{ ok: boolean; status: number; statusText: string; text: string }> {\n const policy = resolveOutboundPolicy(policyInput);\n const response = await guardedFetch(rawUrl, policy, init);\n\n return {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n text: response.ok ? await readTextCapped(response, policy.maxBytes) : \"\",\n };\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,oBAAoB,IAAI,OAAO;;AAErC,MAAM,qBAAqB;;;;;;AAO3B,SAAgB,sBACd,SAAyB,CAAC,GACF;CACxB,OAAO;EACL,gBAAgB,OAAO,kBAAkB,CAAC,OAAO;EACjD,eAAe,OAAO;EACtB,wBAAwB,OAAO,0BAA0B;EACzD,UAAU,OAAO,YAAY;EAC7B,WAAW,OAAO,aAAa;EAC/B,QAAQ,OAAO;EACf,OAAO,OAAO,SAAS,WAAW;CACpC;AACF;;AAGA,SAAS,cAAc,MAAsB;CAC3C,OAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AAC1E;;AAGA,SAAS,YAAY,MAAc,WAA8B;CAC/D,MAAM,QAAQ,KAAK,YAAY;CAC/B,OAAO,UAAU,MAAK,UAAS;EAC7B,MAAM,IAAI,MAAM,YAAY;EAC5B,OAAO,UAAU,KAAK,MAAM,SAAS,IAAI,GAAG;CAC9C,CAAC;AACH;;;;;;;;AASA,eAAsB,iBACpB,QACA,QACc;CACd,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,MAAM;CACtB,QAAQ;EACN,MAAM,IAAI,oBAAoB,2CAA2C,UAAU,EACjF,SAAS,EAAE,KAAK,OAAO,EACzB,CAAC;CACH;CAEA,MAAM,SAAS,IAAI,SAAS,QAAQ,MAAM,EAAE,CAAC,CAAC,YAAY;CAC1D,IAAI,CAAC,OAAO,eAAe,MAAK,MAAK,EAAE,YAAY,MAAM,MAAM,GAC7D,MAAM,IAAI,oBACR,sCAAsC,OAAO,6BAA6B,OAAO,eAAe,KAAK,IAAI,EAAE,IAC3G,EAAE,SAAS;EAAE,KAAK;EAAQ;CAAO,EAAE,CACrC;CAGF,MAAM,OAAO,cAAc,IAAI,QAAQ;CAEvC,IAAI,OAAO,iBAAiB,CAAC,YAAY,MAAM,OAAO,aAAa,GACjE,MAAM,IAAI,oBACR,oCAAoC,KAAK,4BACzC,EAAE,SAAS;EAAE,KAAK;EAAQ;CAAK,EAAE,CACnC;CAGF,IAAI,OAAO,wBACT,MAAM,qBAAqB,MAAM,MAAM;CAGzC,OAAO;AACT;;;;;;;AAQA,eAAe,qBAAqB,MAAc,QAA+B;CAC/E,IAAI,KAAK,IAAI,MAAM,GAAG;EACpB,IAAI,sBAAsB,IAAI,GAC5B,MAAM,IAAI,oBACR,+BAA+B,KAAK,kCACpC,EAAE,SAAS;GAAE,KAAK;GAAQ,SAAS;EAAK,EAAE,CAC5C;EAEF;CACF;CAEA,IAAI;CACJ,IAAI;EACF,YAAY,MAAM,OAAO,MAAM,EAAE,KAAK,KAAK,CAAC;CAC9C,SAAS,OAAO;EACd,MAAM,IAAI,oBACR,sDAAsD,KAAK,2BAC3D;GAAE;GAAO,SAAS;IAAE,KAAK;IAAQ;GAAK;EAAE,CAC1C;CACF;CAEA,KAAK,MAAM,EAAE,aAAa,WACxB,IAAI,sBAAsB,OAAO,GAC/B,MAAM,IAAI,oBACR,oCAAoC,KAAK,4CAA4C,QAAQ,IAC7F,EAAE,SAAS;EAAE,KAAK;EAAQ;EAAM;CAAQ,EAAE,CAC5C;AAGN;;AAGA,SAAS,aACP,SACA,UACa;CACb,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,SAAS,SAAsB,WAAW,MAAM,KAAK,MAAM;CAEjE,IAAI,QAAQ,SAAS,MAAM,OAAO;MAC7B,QAAQ,iBAAiB,eAAe,MAAM,OAAO,GAAG,EAAE,MAAM,KAAK,CAAC;CAE3E,IAAI,SAAS,SAAS,MAAM,QAAQ;MAC/B,SAAS,iBAAiB,eAAe,MAAM,QAAQ,GAAG,EAAE,MAAM,KAAK,CAAC;CAE7E,OAAO,WAAW;AACpB;;;;;;;;AASA,eAAsB,aACpB,QACA,aACA,MACmB;CACnB,MAAM,SAAS,sBAAsB,WAAW;CAChD,MAAM,MAAM,MAAM,iBAAiB,QAAQ,MAAM;CAEjD,MAAM,oBAAoB,IAAI,gBAAgB;CAC9C,MAAM,QAAQ,iBAAiB;EAC7B,kBAAkB,MAChB,IAAI,oBACF,oCAAoC,OAAO,UAAU,KACrD,EAAE,SAAS;GAAE,KAAK;GAAQ,WAAW,OAAO;EAAU,EAAE,CAC1D,CACF;CACF,GAAG,OAAO,SAAS;CAEnB,IAAI;EACF,OAAO,MAAM,OAAO,MAAM,KAAK;GAC7B,GAAG;GACH,QAAQ,aAAa,kBAAkB,QAAQ,OAAO,MAAM;EAC9D,CAAC;CACH,UAAU;EACR,aAAa,KAAK;CACpB;AACF;;;;;;;AAQA,eAAsB,eACpB,UACA,UACiB;CACjB,MAAM,WAAW,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;CAC9D,IAAI,OAAO,SAAS,QAAQ,KAAK,WAAW,UAC1C,MAAM,IAAI,oBACR,+CAA+C,SAAS,qBAAqB,SAAS,YACtF,EAAE,SAAS;EAAE;EAAU;CAAS,EAAE,CACpC;CAGF,IAAI,CAAC,SAAS,MAAM;EAClB,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,IAAI,OAAO,WAAW,IAAI,IAAI,UAC5B,MAAM,IAAI,oBACR,uCAAuC,SAAS,YAChD,EAAE,SAAS,EAAE,SAAS,EAAE,CAC1B;EAEF,OAAO;CACT;CAEA,MAAM,SAAS,SAAS,KAAK,UAAU;CACvC,MAAM,SAAuB,CAAC;CAC9B,IAAI,QAAQ;CAEZ,SAAS;EACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;EAC1C,IAAI,MAAM;EACV,IAAI,CAAC,OAAO;EAEZ,SAAS,MAAM;EACf,IAAI,QAAQ,UAAU;GACpB,MAAM,OAAO,OAAO;GACpB,MAAM,IAAI,oBACR,uCAAuC,SAAS,YAChD,EAAE,SAAS,EAAE,SAAS,EAAE,CAC1B;EACF;EACA,OAAO,KAAK,KAAK;CACnB;CAEA,OAAO,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,MAAM;AAC9C;;;;;;AAOA,eAAsB,oBACpB,QACA,aACA,MAC4E;CAC5E,MAAM,SAAS,sBAAsB,WAAW;CAChD,MAAM,WAAW,MAAM,aAAa,QAAQ,QAAQ,IAAI;CAExD,OAAO;EACL,IAAI,SAAS;EACb,QAAQ,SAAS;EACjB,YAAY,SAAS;EACrB,MAAM,SAAS,KAAK,MAAM,eAAe,UAAU,OAAO,QAAQ,IAAI;CACxE;AACF"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/security/outbound-policy.type.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* One shared policy for every server-side outbound request the framework
|
|
4
|
+
* makes on a user's behalf — attachment fetches (S1), URL skill manifests
|
|
5
|
+
* (S3), RAG document loaders (A4), and any future HTTP helper. Centralizing
|
|
6
|
+
* the controls here means a single, audited SSRF / resource-exhaustion
|
|
7
|
+
* guard instead of six ad-hoc `fetch()` call sites.
|
|
8
|
+
*
|
|
9
|
+
* Every field is optional; {@link resolveOutboundPolicy} fills safe
|
|
10
|
+
* defaults. The defaults are deliberately strict (https-only, private-IP
|
|
11
|
+
* deny on, 10s timeout, 5 MiB cap) so a caller that opts into outbound
|
|
12
|
+
* fetch without tuning still gets a hardened request.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const policy: OutboundPolicy = {
|
|
16
|
+
* allowedSchemes: ["https"],
|
|
17
|
+
* hostAllowlist: ["cdn.example.com"],
|
|
18
|
+
* maxBytes: 1_000_000,
|
|
19
|
+
* timeoutMs: 5_000,
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
type OutboundPolicy = {
|
|
23
|
+
/**
|
|
24
|
+
* URL schemes permitted for the request. Compared case-insensitively
|
|
25
|
+
* against the URL's protocol (without the trailing colon). Default
|
|
26
|
+
* `["https"]` — `http` must be opted in explicitly.
|
|
27
|
+
*/
|
|
28
|
+
allowedSchemes?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Host allowlist. When set, the request host must equal one of these
|
|
31
|
+
* entries or be a subdomain of one (`cdn.example.com` allows
|
|
32
|
+
* `a.cdn.example.com`). When omitted, any host passes the allowlist
|
|
33
|
+
* check — but the private-IP guard below still applies.
|
|
34
|
+
*/
|
|
35
|
+
hostAllowlist?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the host through DNS and reject when it maps to a private,
|
|
38
|
+
* loopback, link-local, unique-local, or cloud-metadata
|
|
39
|
+
* (`169.254.169.254`) address — the core SSRF guard. Catches a public
|
|
40
|
+
* hostname that resolves inward. Default `true`.
|
|
41
|
+
*/
|
|
42
|
+
denyPrivateIPsAfterDNS?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Maximum response body size in bytes. A declared `content-length`
|
|
45
|
+
* over this fails fast; otherwise the body is read with a running cap
|
|
46
|
+
* and aborted on overflow. Default `5_242_880` (5 MiB).
|
|
47
|
+
*/
|
|
48
|
+
maxBytes?: number; /** Per-request timeout in milliseconds. Default `10_000`. */
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Caller `AbortSignal`, merged with the internal timeout — whichever
|
|
52
|
+
* fires first aborts the request.
|
|
53
|
+
*/
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
/**
|
|
56
|
+
* Injected `fetch` implementation (for tests, proxies, or a wrapper
|
|
57
|
+
* that already enforces app-level SSRF rules). Defaults to the global
|
|
58
|
+
* `fetch`.
|
|
59
|
+
*/
|
|
60
|
+
fetch?: typeof fetch;
|
|
61
|
+
};
|
|
62
|
+
/** {@link OutboundPolicy} with every default resolved — never partial. */
|
|
63
|
+
type ResolvedOutboundPolicy = {
|
|
64
|
+
allowedSchemes: string[];
|
|
65
|
+
hostAllowlist?: string[];
|
|
66
|
+
denyPrivateIPsAfterDNS: boolean;
|
|
67
|
+
maxBytes: number;
|
|
68
|
+
timeoutMs: number;
|
|
69
|
+
signal?: AbortSignal;
|
|
70
|
+
fetch: typeof fetch;
|
|
71
|
+
};
|
|
72
|
+
//#endregion
|
|
73
|
+
export { OutboundPolicy, ResolvedOutboundPolicy };
|
|
74
|
+
//# sourceMappingURL=outbound-policy.type.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-policy.type.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/outbound-policy.type.ts"],"mappings":";;AAoBA;;;;;;;;;;;;;;AAuCsB;AAItB;;;;KA3CY,cAAA;EA6CV;;;;;EAvCA,cAAA;EA4CA;;;AAAmB;;;EArCnB,aAAA;;;;;;;EAOA,sBAAA;;;;;;EAMA,QAAA;EAEA,SAAA;;;;;EAKA,MAAA,GAAS,WAAA;;;;;;EAMT,KAAA,UAAe,KAAK;AAAA;;KAIV,sBAAA;EACV,cAAA;EACA,aAAA;EACA,sBAAA;EACA,QAAA;EACA,SAAA;EACA,MAAA,GAAS,WAAA;EACT,KAAA,SAAc,KAAK;AAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/security/private-ip.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* True when `ip` is a private, loopback, link-local, unique-local,
|
|
4
|
+
* carrier-grade-NAT, unspecified, or otherwise non-public address — the
|
|
5
|
+
* set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including
|
|
6
|
+
* IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns
|
|
7
|
+
* `false` (the caller resolves hostnames via DNS first).
|
|
8
|
+
*
|
|
9
|
+
* The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4
|
|
10
|
+
* link-local range `169.254.0.0/16`.
|
|
11
|
+
*/
|
|
12
|
+
declare function isPrivateOrReservedIp(ip: string): boolean;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { isPrivateOrReservedIp };
|
|
15
|
+
//# sourceMappingURL=private-ip.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-ip.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/private-ip.ts"],"mappings":";;AAYA;;;;AAAgD;;;;;iBAAhC,qBAAA,CAAsB,EAAU"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai/src/security/private-ip.ts
|
|
4
|
+
/**
|
|
5
|
+
* True when `ip` is a private, loopback, link-local, unique-local,
|
|
6
|
+
* carrier-grade-NAT, unspecified, or otherwise non-public address — the
|
|
7
|
+
* set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including
|
|
8
|
+
* IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns
|
|
9
|
+
* `false` (the caller resolves hostnames via DNS first).
|
|
10
|
+
*
|
|
11
|
+
* The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4
|
|
12
|
+
* link-local range `169.254.0.0/16`.
|
|
13
|
+
*/
|
|
14
|
+
function isPrivateOrReservedIp(ip) {
|
|
15
|
+
const family = isIP(ip);
|
|
16
|
+
if (family === 4) return isPrivateIpv4(ip);
|
|
17
|
+
if (family === 6) return isPrivateIpv6(ip);
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
/** Parse a dotted-quad into four octets, or `null` if malformed. */
|
|
21
|
+
function parseIpv4(ip) {
|
|
22
|
+
const parts = ip.split(".");
|
|
23
|
+
if (parts.length !== 4) return null;
|
|
24
|
+
const octets = parts.map((part) => Number(part));
|
|
25
|
+
if (octets.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
|
|
26
|
+
return octets;
|
|
27
|
+
}
|
|
28
|
+
function isPrivateIpv4(ip) {
|
|
29
|
+
const octets = parseIpv4(ip);
|
|
30
|
+
if (!octets) return true;
|
|
31
|
+
const [a, b] = octets;
|
|
32
|
+
return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 192 && b === 0 || a === 198 && (b === 18 || b === 19) || a === 198 && b === 51 || a === 203 && b === 0 || a >= 224;
|
|
33
|
+
}
|
|
34
|
+
function isPrivateIpv6(ip) {
|
|
35
|
+
const normalized = ip.toLowerCase().split("%")[0];
|
|
36
|
+
const v4 = normalized.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
|
|
37
|
+
if (v4) return isPrivateIpv4(v4[1]);
|
|
38
|
+
if (normalized === "::1" || normalized === "::") return true;
|
|
39
|
+
const firstGroup = normalized.split(":")[0];
|
|
40
|
+
const head = firstGroup === "" ? 0 : Number.parseInt(firstGroup, 16);
|
|
41
|
+
if ((head & 65024) === 64512) return true;
|
|
42
|
+
if ((head & 65472) === 65152) return true;
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { isPrivateOrReservedIp };
|
|
48
|
+
//# sourceMappingURL=private-ip.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-ip.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/private-ip.ts"],"sourcesContent":["import { isIP } from \"node:net\";\n\n/**\n * True when `ip` is a private, loopback, link-local, unique-local,\n * carrier-grade-NAT, unspecified, or otherwise non-public address — the\n * set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including\n * IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns\n * `false` (the caller resolves hostnames via DNS first).\n *\n * The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4\n * link-local range `169.254.0.0/16`.\n */\nexport function isPrivateOrReservedIp(ip: string): boolean {\n const family = isIP(ip);\n if (family === 4) return isPrivateIpv4(ip);\n if (family === 6) return isPrivateIpv6(ip);\n return false;\n}\n\n/** Parse a dotted-quad into four octets, or `null` if malformed. */\nfunction parseIpv4(ip: string): [number, number, number, number] | null {\n const parts = ip.split(\".\");\n if (parts.length !== 4) return null;\n\n const octets = parts.map(part => Number(part));\n if (octets.some(n => !Number.isInteger(n) || n < 0 || n > 255)) return null;\n\n return octets as [number, number, number, number];\n}\n\nfunction isPrivateIpv4(ip: string): boolean {\n const octets = parseIpv4(ip);\n if (!octets) return true; // unparseable → refuse, fail closed\n\n const [a, b] = octets;\n\n return (\n a === 0 || // 0.0.0.0/8 \"this network\"\n a === 10 || // 10.0.0.0/8 private\n a === 127 || // 127.0.0.0/8 loopback\n (a === 100 && b >= 64 && b <= 127) || // 100.64.0.0/10 CGNAT\n (a === 169 && b === 254) || // 169.254.0.0/16 link-local + metadata\n (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 private\n (a === 192 && b === 168) || // 192.168.0.0/16 private\n (a === 192 && b === 0) || // 192.0.0.0/24 + 192.0.2.0/24 (IETF/test)\n (a === 198 && (b === 18 || b === 19)) || // 198.18.0.0/15 benchmarking\n (a === 198 && b === 51) || // 198.51.100.0/24 test-net-2\n (a === 203 && b === 0) || // 203.0.113.0/24 test-net-3\n a >= 224 // 224.0.0.0/4 multicast + 240.0.0.0/4 reserved + 255.255.255.255\n );\n}\n\nfunction isPrivateIpv6(ip: string): boolean {\n const normalized = ip.toLowerCase().split(\"%\")[0]; // drop zone id\n\n // IPv4-mapped / -embedded (::ffff:a.b.c.d, ::a.b.c.d) — defer to the v4\n // check on the trailing dotted-quad so an inward-mapped address is caught.\n const v4 = normalized.match(/(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/);\n if (v4) {\n return isPrivateIpv4(v4[1]);\n }\n\n if (normalized === \"::1\" || normalized === \"::\") {\n return true; // loopback / unspecified\n }\n\n // Expand only the leading group enough to classify the reserved blocks.\n const firstGroup = normalized.split(\":\")[0];\n const head = firstGroup === \"\" ? 0 : Number.parseInt(firstGroup, 16);\n\n // fc00::/7 unique-local (fc.. / fd..)\n if ((head & 0xfe00) === 0xfc00) return true;\n // fe80::/10 link-local\n if ((head & 0xffc0) === 0xfe80) return true;\n\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,sBAAsB,IAAqB;CACzD,MAAM,SAAS,KAAK,EAAE;CACtB,IAAI,WAAW,GAAG,OAAO,cAAc,EAAE;CACzC,IAAI,WAAW,GAAG,OAAO,cAAc,EAAE;CACzC,OAAO;AACT;;AAGA,SAAS,UAAU,IAAqD;CACtE,MAAM,QAAQ,GAAG,MAAM,GAAG;CAC1B,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,MAAM,SAAS,MAAM,KAAI,SAAQ,OAAO,IAAI,CAAC;CAC7C,IAAI,OAAO,MAAK,MAAK,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;CAEvE,OAAO;AACT;AAEA,SAAS,cAAc,IAAqB;CAC1C,MAAM,SAAS,UAAU,EAAE;CAC3B,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,CAAC,GAAG,KAAK;CAEf,OACE,MAAM,KACN,MAAM,MACN,MAAM,OACL,MAAM,OAAO,KAAK,MAAM,KAAK,OAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,KAAK,MAAM,KAAK,MAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,MAAM,KACnB,MAAM,QAAQ,MAAM,MAAM,MAAM,OAChC,MAAM,OAAO,MAAM,MACnB,MAAM,OAAO,MAAM,KACpB,KAAK;AAET;AAEA,SAAS,cAAc,IAAqB;CAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;CAI/C,MAAM,KAAK,WAAW,MAAM,uCAAuC;CACnE,IAAI,IACF,OAAO,cAAc,GAAG,EAAE;CAG5B,IAAI,eAAe,SAAS,eAAe,MACzC,OAAO;CAIT,MAAM,aAAa,WAAW,MAAM,GAAG,CAAC,CAAC;CACzC,MAAM,OAAO,eAAe,KAAK,IAAI,OAAO,SAAS,YAAY,EAAE;CAGnE,KAAK,OAAO,WAAY,OAAQ,OAAO;CAEvC,KAAK,OAAO,WAAY,OAAQ,OAAO;CAEvC,OAAO;AACT"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai/src/security/redact.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Default set of sensitive key fragments (matched case-insensitively as
|
|
4
|
+
* substrings of an object key). Covers the secrets that leak through
|
|
5
|
+
* recorded requests, error causes, and trace payloads: auth headers, API
|
|
6
|
+
* keys, cookies, tokens, passwords, and private keys.
|
|
7
|
+
*/
|
|
8
|
+
declare const DEFAULT_SENSITIVE_KEYS: readonly string[];
|
|
9
|
+
/** HTTP header names always stripped from a serialized error/cause. */
|
|
10
|
+
declare const SENSITIVE_HEADERS: readonly string[];
|
|
11
|
+
type RedactOptions = {
|
|
12
|
+
/** Extra key fragments to redact, merged with {@link DEFAULT_SENSITIVE_KEYS}. */keys?: string[]; /** Replacement for a redacted value. Default `"[redacted]"`. */
|
|
13
|
+
placeholder?: string; /** Maximum recursion depth before bailing out. Default `8`. */
|
|
14
|
+
maxDepth?: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Deep-copy `value` with any property whose KEY matches a sensitive
|
|
18
|
+
* fragment replaced by the placeholder. Arrays are walked element-wise;
|
|
19
|
+
* circular references and over-deep trees collapse to the placeholder.
|
|
20
|
+
* Primitives pass through untouched (redaction is key-driven, not
|
|
21
|
+
* value-driven — it never guesses at a bare string being a secret).
|
|
22
|
+
*
|
|
23
|
+
* Shared by VCR cassettes (S2), Panoptic content capture, and the error /
|
|
24
|
+
* cause serializer (S4) so there is ONE redaction policy, not three.
|
|
25
|
+
*/
|
|
26
|
+
declare function redact<T>(value: T, options?: RedactOptions): T;
|
|
27
|
+
/**
|
|
28
|
+
* Strip sensitive HTTP headers from a `Headers` instance or a plain
|
|
29
|
+
* header record, returning a redacted plain object. Header names are
|
|
30
|
+
* matched case-insensitively against {@link SENSITIVE_HEADERS}.
|
|
31
|
+
*/
|
|
32
|
+
declare function redactHeaders(headers: Headers | Record<string, unknown> | undefined, placeholder?: string): Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* Scrub secrets that appear in free-form text — error messages, stack
|
|
35
|
+
* traces, exported log lines. Complements {@link redact} (which is key-
|
|
36
|
+
* driven and can't see a token embedded in a string). Used by the trace /
|
|
37
|
+
* error serializer (S4) before a message or stack is stored or exported.
|
|
38
|
+
*/
|
|
39
|
+
declare function scrubSecrets(text: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Serialized, secret-free view of an error. `stack` is omitted by default
|
|
42
|
+
* (it can embed local paths, endpoints, and tokens); pass
|
|
43
|
+
* `includeStack: true` only for a trusted local sink. The retained
|
|
44
|
+
* `cause` is deep-redacted via {@link redact}, so a raw provider SDK error
|
|
45
|
+
* carrying `Authorization` / `x-api-key` on `cause.headers` is sanitized.
|
|
46
|
+
*/
|
|
47
|
+
type RedactedError = {
|
|
48
|
+
name: string;
|
|
49
|
+
message: string;
|
|
50
|
+
code?: string;
|
|
51
|
+
cause?: unknown;
|
|
52
|
+
stack?: string;
|
|
53
|
+
};
|
|
54
|
+
declare function redactError(error: unknown, options?: {
|
|
55
|
+
includeStack?: boolean;
|
|
56
|
+
} & RedactOptions): RedactedError;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { DEFAULT_SENSITIVE_KEYS, RedactOptions, RedactedError, SENSITIVE_HEADERS, redact, redactError, redactHeaders, scrubSecrets };
|
|
59
|
+
//# sourceMappingURL=redact.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/redact.ts"],"mappings":";;AAMA;;;;AAgBC;cAhBY,sBAAA;;cAmBA,iBAAA;AAAA,KASD,aAAA;EAFX,iFAIC,IAAA,aAFuB;EAIvB,WAAA,WAJuB;EAMvB,QAAA;AAAA;;;AAAQ;AAqBV;;;;;;;iBAAgB,MAAA,IAAU,KAAA,EAAO,CAAA,EAAG,OAAA,GAAS,aAAA,GAAqB,CAAA;;;;;;iBAsClD,aAAA,CACd,OAAA,EAAS,OAAA,GAAU,MAAA,+BACnB,WAAA,YACC,MAAA;;AAzCgE;AAsCnE;;;;iBAuCgB,YAAA,CAAa,IAAY;;;;;;;;KAe7B,aAAA;EACV,IAAA;EACA,OAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,iBAGc,WAAA,CACd,KAAA,WACA,OAAA;EAAW,YAAA;AAAA,IAA2B,aAAA,GACrC,aAAa"}
|