@planu/cli 4.14.1 → 5.1.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/CHANGELOG.md +82 -0
- package/LICENSE +55 -12
- package/README.md +10 -2
- package/dist/cli/commands/install.d.ts +1 -12
- package/dist/cli/commands/install.js +9 -65
- package/dist/cli/commands/job.js +4 -3
- package/dist/cli/commands/spec.js +12 -3
- package/dist/cli/commands/validate.js +2 -2
- package/dist/cli/router.js +1 -3
- package/dist/config/environment-schema.json +1 -3
- package/dist/config/official-sdd-tools.d.ts +4 -0
- package/dist/config/official-sdd-tools.js +35 -0
- package/dist/config/product-public.d.ts +139 -3
- package/dist/config/product-public.js +8 -1
- package/dist/config/product-public.json +7 -36
- package/dist/config/registries/hosts/codex.json +20 -363
- package/dist/config/release-policy.json +84 -2
- package/dist/config/runtime-policy.json +12 -1
- package/dist/config/skill-templates/planu-resume-work.md +2 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/core/spec-validator.d.ts +4 -4
- package/dist/core/spec-validator.js +33 -19
- package/dist/engine/abortable-process-runner.d.ts +20 -2
- package/dist/engine/abortable-process-runner.js +243 -74
- package/dist/engine/ambiguity-scorer.js +4 -26
- package/dist/engine/auth/scope-mapper.js +1 -7
- package/dist/engine/autopilot/state-updater.js +4 -4
- package/dist/engine/cascade-hooks/hooks/review-enricher.hook.js +9 -6
- package/dist/engine/cascade-hooks/state-drift-detector.d.ts +3 -3
- package/dist/engine/cascade-hooks/state-drift-detector.js +1 -1
- package/dist/engine/ci-generator/planu-config.js +1 -7
- package/dist/engine/clarification-gate/gate.d.ts +3 -3
- package/dist/engine/code-scanner/layer-scanner.js +6 -22
- package/dist/engine/core-bridge.d.ts +3 -3
- package/dist/engine/cost-guardrails.d.ts +1 -1
- package/dist/engine/cost-guardrails.js +1 -1
- package/dist/engine/criterion-identity.d.ts +1 -0
- package/dist/engine/criterion-identity.js +7 -0
- package/dist/engine/dashboard/data-loader.js +2 -7
- package/dist/engine/dashboard/templates-layout.js +0 -3
- package/dist/engine/dashboard/templates-project.js +1 -13
- package/dist/engine/docs-site-generator/data-collector.d.ts +1 -1
- package/dist/engine/docs-site-generator/data-collector.js +7 -28
- package/dist/engine/docs-site-generator/tools-renderer.js +3 -10
- package/dist/engine/evidence-gates/artifact-reader.d.ts +12 -1
- package/dist/engine/evidence-gates/artifact-reader.js +174 -4
- package/dist/engine/evidence-gates/evidence-autofill.d.ts +10 -0
- package/dist/engine/evidence-gates/evidence-autofill.js +148 -0
- package/dist/engine/evidence-gates/evidence-skeletons.d.ts +19 -0
- package/dist/engine/evidence-gates/evidence-skeletons.js +69 -0
- package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
- package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
- package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
- package/dist/engine/evidence-index/done-drift.d.ts +1 -1
- package/dist/engine/evidence-index/done-drift.js +40 -18
- package/dist/engine/execution/context.js +3 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
- package/dist/engine/execution/job-runtime.d.ts +30 -0
- package/dist/engine/execution/job-runtime.js +114 -6
- package/dist/engine/execution/operation-journal.js +10 -4
- package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
- package/dist/engine/execution/public-job-sanitizer.js +31 -0
- package/dist/engine/execution/validate-job-executor.d.ts +12 -1
- package/dist/engine/execution/validate-job-executor.js +549 -86
- package/dist/engine/execution/validate-job-payload.js +107 -50
- package/dist/engine/execution/validate-job-recovery.js +1 -1
- package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
- package/dist/engine/execution/validate-worker-runtime.js +90 -2
- package/dist/engine/execution/validate-worker-thread.js +17 -24
- package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
- package/dist/engine/handoff-artifacts/schemas.js +33 -0
- package/dist/engine/handoff-packager.d.ts +19 -0
- package/dist/engine/handoff-packager.js +415 -13
- package/dist/engine/hooks/effort-configurator.js +1 -1
- package/dist/engine/impact-detector/test-break-predictor.js +3 -3
- package/dist/engine/impact-detector/tool-registration.js +1 -1
- package/dist/engine/implementation-contract/renderer.js +23 -8
- package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
- package/dist/engine/lifecycle-reconciliation-io.js +180 -0
- package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
- package/dist/engine/lifecycle-reconciliation.js +406 -0
- package/dist/engine/local-first/tool-classification.js +2 -0
- package/dist/engine/macos-keychain-native-port.d.ts +5 -0
- package/dist/engine/macos-keychain-native-port.js +19 -7
- package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
- package/dist/engine/migrations/remove-commercial-state.js +343 -0
- package/dist/engine/minimality/policy-loader.js +247 -6
- package/dist/engine/network-policy.js +1 -0
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +20 -20
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +20 -20
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +20 -20
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +20 -20
- package/dist/engine/readiness-checker.d.ts +1 -16
- package/dist/engine/readiness-checker.js +27 -88
- package/dist/engine/reverse-engineer/api-detector.js +2 -13
- package/dist/engine/reverse-engineer/complexity-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/config-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/dependency-graph.js +2 -13
- package/dist/engine/reverse-engineer/test-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/walk-ignore.d.ts +3 -0
- package/dist/engine/reverse-engineer/walk-ignore.js +26 -0
- package/dist/engine/runtime-policy.d.ts +2 -0
- package/dist/engine/runtime-policy.js +42 -5
- package/dist/engine/runtime-security/rate-limiter.js +0 -1
- package/dist/engine/safety/contained-project-file.d.ts +3 -0
- package/dist/engine/safety/contained-project-file.js +23 -0
- package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
- package/dist/engine/scope-boundaries/scope-validator.js +45 -7
- package/dist/engine/session/checkpoint-writer.js +0 -9
- package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
- package/dist/engine/spec-format/acceptance-criteria.js +82 -22
- package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
- package/dist/engine/spec-format/markdown-sections.js +105 -0
- package/dist/engine/spec-format/read-technical-section.js +33 -5
- package/dist/engine/spec-format/technical-md-populator.js +3 -2
- package/dist/engine/spec-format/text-fences.js +20 -2
- package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
- package/dist/engine/spec-format/unified-spec-builder.js +202 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
- package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
- package/dist/engine/spec-migrator/filesystem-import.js +121 -14
- package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
- package/dist/engine/spec-migrator/index.d.ts +1 -0
- package/dist/engine/spec-migrator/index.js +1 -0
- package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
- package/dist/engine/spec-state-machine/transition-spec.js +10 -1
- package/dist/engine/spec-state-syncer.js +1 -1
- package/dist/engine/technical-enricher/index.js +16 -8
- package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
- package/dist/engine/technical-enricher/render-enriched.js +42 -14
- package/dist/engine/telemetry/health-checker.js +53 -17
- package/dist/engine/telemetry/telemetry-client.js +26 -8
- package/dist/engine/text-signal-boundaries.d.ts +2 -0
- package/dist/engine/text-signal-boundaries.js +25 -2
- package/dist/engine/time/relative-date.d.ts +3 -0
- package/dist/engine/time/relative-date.js +16 -0
- package/dist/engine/timing/budget.d.ts +11 -0
- package/dist/engine/timing/budget.js +31 -9
- package/dist/engine/token-optimizer/analytics.d.ts +1 -1
- package/dist/engine/token-optimizer/analytics.js +5 -6
- package/dist/engine/usage-tracker/core.d.ts +2 -2
- package/dist/engine/usage-tracker/core.js +1 -2
- package/dist/engine/usage-tracker/index.d.ts +0 -3
- package/dist/engine/usage-tracker/index.js +0 -3
- package/dist/engine/usage-tracker/stats.d.ts +2 -2
- package/dist/engine/usage-tracker/stats.js +1 -28
- package/dist/engine/validation/durable-validation.d.ts +1 -1
- package/dist/engine/validation/durable-validation.js +3 -82
- package/dist/engine/validation/validation-freshness.d.ts +11 -1
- package/dist/engine/validation/validation-freshness.js +231 -91
- package/dist/engine/validation/validation-receipt.d.ts +9 -6
- package/dist/engine/validation/validation-receipt.js +84 -24
- package/dist/engine/validation/validation-source-digest.d.ts +2 -0
- package/dist/engine/validation/validation-source-digest.js +86 -0
- package/dist/engine/validation/validation-submission.d.ts +5 -4
- package/dist/engine/validation/validation-submission.js +25 -11
- package/dist/engine/validation/validation-worktree.d.ts +21 -0
- package/dist/engine/validation/validation-worktree.js +260 -0
- package/dist/engine/validation-impact-planner.d.ts +14 -2
- package/dist/engine/validation-impact-planner.js +0 -3
- package/dist/engine/validator/dor-dod.d.ts +1 -0
- package/dist/engine/validator/dor-dod.js +5 -3
- package/dist/engine/validator/extractors.d.ts +1 -5
- package/dist/engine/validator/extractors.js +24 -69
- package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
- package/dist/engine/validator/spec-compliance-runner.js +429 -211
- package/dist/engine/validator.js +35 -22
- package/dist/index.js +4 -16
- package/dist/resources/usage-stats-resource.js +2 -18
- package/dist/security/adapters/linux-secret-service.js +7 -3
- package/dist/security/adapters/windows-credential-manager.js +6 -4
- package/dist/server/routes/specs.js +13 -1
- package/dist/storage/base-store.d.ts +1 -1
- package/dist/storage/base-store.js +1 -1
- package/dist/storage/feedback-remote.d.ts +2 -3
- package/dist/storage/feedback-remote.js +45 -31
- package/dist/storage/global-store.d.ts +1 -17
- package/dist/storage/global-store.js +1 -42
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.js +0 -2
- package/dist/storage/migrations/canonical-storage.js +124 -11
- package/dist/storage/runtime-db.d.ts +9 -0
- package/dist/storage/runtime-db.js +64 -8
- package/dist/storage/spec-store.d.ts +14 -2
- package/dist/storage/spec-store.js +104 -14
- package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
- package/dist/storage/status-store/atomic-status-write.js +57 -0
- package/dist/storage/status-store/file-lock.js +30 -11
- package/dist/storage/status-store/self-healing.js +3 -3
- package/dist/storage/status-store/version-sync.d.ts +2 -1
- package/dist/storage/status-store/version-sync.js +35 -40
- package/dist/storage/usage-store.d.ts +1 -5
- package/dist/storage/usage-store.js +0 -35
- package/dist/tools/auto-update-handler.d.ts +3 -3
- package/dist/tools/auto-update-handler.js +3 -3
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
- package/dist/tools/challenge-spec/scenario-collector.js +1 -1
- package/dist/tools/challenge-spec/scenarios-data.js +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
- package/dist/tools/challenge-spec-helpers.d.ts +10 -1
- package/dist/tools/challenge-spec-helpers.js +63 -22
- package/dist/tools/challenge-spec.js +23 -8
- package/dist/tools/check-readiness.js +38 -14
- package/dist/tools/configure-telemetry.js +30 -2
- package/dist/tools/create-spec/spec-builder.d.ts +7 -0
- package/dist/tools/create-spec/spec-builder.js +19 -15
- package/dist/tools/create-spec.d.ts +1 -0
- package/dist/tools/create-spec.js +584 -309
- package/dist/tools/git/branch-ops.d.ts +1 -1
- package/dist/tools/git/branch-ops.js +3 -2
- package/dist/tools/init-project/handler.js +10 -12
- package/dist/tools/init-project/host-assets-writer.js +26 -1
- package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
- package/dist/tools/init-project/migration-runner.d.ts +2 -4
- package/dist/tools/init-project/migration-runner.js +3 -2
- package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
- package/dist/tools/init-project/portable-index-reconciler.js +14 -0
- package/dist/tools/init-project/result-builder.js +1 -3
- package/dist/tools/jobs/handlers.js +38 -6
- package/dist/tools/list-specs.js +5 -26
- package/dist/tools/merge-risk-handler.js +2 -2
- package/dist/tools/package-handoff.js +2 -0
- package/dist/tools/reconcile-spec.js +0 -27
- package/dist/tools/register-agent-squad-tools.js +2 -2
- package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
- package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-sdd-tools.js +2 -29
- package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
- package/dist/tools/register-spec-tools/core-spec-tools.js +29 -19
- package/dist/tools/safe-handler.d.ts +5 -13
- package/dist/tools/safe-handler.js +7 -23
- package/dist/tools/schemas/index.d.ts +1 -1
- package/dist/tools/schemas/index.js +1 -1
- package/dist/tools/schemas/output-schemas.d.ts +0 -23
- package/dist/tools/schemas/output-schemas.js +0 -28
- package/dist/tools/schemas/spec.d.ts +4 -0
- package/dist/tools/schemas/spec.js +3 -0
- package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
- package/dist/tools/schemas/validate-output-schema.js +7 -0
- package/dist/tools/spec-prompt-handler.js +3 -3
- package/dist/tools/sync-spec-state-handler.d.ts +1 -1
- package/dist/tools/sync-spec-state-handler.js +50 -2
- package/dist/tools/tool-entry.d.ts +4 -4
- package/dist/tools/tool-entry.js +3 -3
- package/dist/tools/tool-registry/core-tools.js +31 -15
- package/dist/tools/tool-registry/group-infra.js +27 -110
- package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
- package/dist/tools/tool-registry/inventory.d.ts +2 -0
- package/dist/tools/tool-registry/inventory.js +2 -0
- package/dist/tools/tool-registry-helpers.d.ts +3 -3
- package/dist/tools/tool-registry-helpers.js +3 -3
- package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
- package/dist/tools/tool-usage-report/registered-tools.js +3 -15
- package/dist/tools/update-status/approval-gates.js +3 -0
- package/dist/tools/update-status/batch.d.ts +6 -2
- package/dist/tools/update-status/batch.js +58 -1
- package/dist/tools/update-status/dod-gates.d.ts +16 -1
- package/dist/tools/update-status/dod-gates.js +191 -1
- package/dist/tools/update-status/done-receipt-verifier.d.ts +8 -0
- package/dist/tools/update-status/done-receipt-verifier.js +75 -27
- package/dist/tools/update-status/evidence-gate.d.ts +4 -0
- package/dist/tools/update-status/evidence-gate.js +103 -3
- package/dist/tools/update-status/file-sync.d.ts +4 -3
- package/dist/tools/update-status/file-sync.js +57 -6
- package/dist/tools/update-status/index.d.ts +25 -1
- package/dist/tools/update-status/index.js +292 -78
- package/dist/tools/update-status/response-builder.js +3 -3
- package/dist/tools/update-status/side-effects.d.ts +2 -0
- package/dist/tools/update-status/side-effects.js +2 -2
- package/dist/tools/update-status/transition-guard.js +45 -16
- package/dist/tools/update-status-actions.d.ts +4 -2
- package/dist/tools/update-status-actions.js +16 -14
- package/dist/tools/usage-report.js +1 -16
- package/dist/tools/usage-stats.js +1 -18
- package/dist/tools/usage-tracking.d.ts +4 -0
- package/dist/tools/usage-tracking.js +20 -0
- package/dist/tools/validate-lint.d.ts +1 -0
- package/dist/tools/validate-lint.js +1 -1
- package/dist/tools/validate.d.ts +2 -1
- package/dist/tools/validate.js +114 -34
- package/dist/tools/workspace-dashboard-handler.js +38 -0
- package/dist/transports/http-transport.js +6 -8
- package/dist/transports/mcp-types.d.ts +0 -2
- package/dist/transports/session-context.js +1 -1
- package/dist/types/cascade-hooks.d.ts +1 -1
- package/dist/types/ci.d.ts +0 -4
- package/dist/types/clarification-token.d.ts +1 -1
- package/dist/types/claude-code-runtime.d.ts +0 -27
- package/dist/types/commercial-migration.d.ts +17 -0
- package/dist/types/commercial-migration.js +2 -0
- package/dist/types/common/primitives.d.ts +0 -2
- package/dist/types/core-bridge.d.ts +4 -10
- package/dist/types/dashboard.d.ts +3 -7
- package/dist/types/docs.d.ts +0 -1
- package/dist/types/durable-job.d.ts +4 -4
- package/dist/types/durable-validation.d.ts +100 -2
- package/dist/types/durable-validation.js +165 -1
- package/dist/types/errors/structured-error.d.ts +3 -3
- package/dist/types/estimation.d.ts +2 -0
- package/dist/types/evidence-autofill.d.ts +34 -0
- package/dist/types/evidence-autofill.js +2 -0
- package/dist/types/evidence-gates.d.ts +9 -1
- package/dist/types/execution.d.ts +2 -0
- package/dist/types/gemini-integration.d.ts +0 -11
- package/dist/types/handoff-artifacts.d.ts +41 -0
- package/dist/types/hooks-advanced.d.ts +0 -13
- package/dist/types/impact-detection.d.ts +2 -2
- package/dist/types/index.d.ts +3 -6
- package/dist/types/index.js +2 -5
- package/dist/types/kiro-integration.d.ts +0 -6
- package/dist/types/network-policy.d.ts +1 -1
- package/dist/types/project/lint-scaffolder.d.ts +1 -1
- package/dist/types/runtime-policy.d.ts +11 -0
- package/dist/types/session-safeguard.d.ts +0 -31
- package/dist/types/spec/canonical-repair.d.ts +81 -0
- package/dist/types/spec/canonical-repair.js +2 -0
- package/dist/types/spec/core.d.ts +20 -0
- package/dist/types/spec/index.d.ts +1 -0
- package/dist/types/spec/index.js +1 -0
- package/dist/types/spec/inputs.d.ts +35 -1
- package/dist/types/spec-format.d.ts +25 -1
- package/dist/types/telemetry.d.ts +4 -1
- package/dist/types/transition-log.d.ts +1 -1
- package/dist/types/transport.d.ts +0 -2
- package/dist/types/usage.d.ts +1 -36
- package/dist/types/usage.js +1 -1
- package/dist/types/validate-worker.d.ts +6 -0
- package/dist/types/validation-receipt.d.ts +1 -1
- package/dist/types/validation.d.ts +10 -4
- package/package.json +17 -12
- package/planu-native.json +1 -1
- package/planu-plugin.json +23 -40
- package/scripts/lib/pending-release-file.mjs +93 -0
- package/src/i18n/messages/en.json +0 -41
- package/src/i18n/messages/es.json +0 -41
- package/src/i18n/messages/pt.json +0 -41
- package/dist/cli/commands/activate.d.ts +0 -14
- package/dist/cli/commands/activate.js +0 -174
- package/dist/config/license-plans.json +0 -251
- package/dist/config/product-public.ts +0 -148
- package/dist/config/server-instructions.ts +0 -121
- package/dist/config/version-defaults.ts +0 -76
- package/dist/config/version.ts +0 -21
- package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
- package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
- package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
- package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
- package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
- package/dist/engine/hooks/full-spectrum-generator.js +0 -117
- package/dist/engine/license-validator/config-loader.d.ts +0 -5
- package/dist/engine/license-validator/config-loader.js +0 -16
- package/dist/engine/license-validator/core.d.ts +0 -15
- package/dist/engine/license-validator/core.js +0 -151
- package/dist/engine/license-validator/fingerprint.d.ts +0 -3
- package/dist/engine/license-validator/fingerprint.js +0 -17
- package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
- package/dist/engine/license-validator/lemon-squeezy.js +0 -55
- package/dist/engine/license-validator.d.ts +0 -5
- package/dist/engine/license-validator.js +0 -6
- package/dist/engine/product-intelligence/index.d.ts +0 -7
- package/dist/engine/product-intelligence/index.js +0 -211
- package/dist/engine/session/auto-save.d.ts +0 -18
- package/dist/engine/session/auto-save.js +0 -98
- package/dist/engine/session/context-snapshot.d.ts +0 -8
- package/dist/engine/session/context-snapshot.js +0 -49
- package/dist/engine/session/memory-sync.d.ts +0 -12
- package/dist/engine/session/memory-sync.js +0 -34
- package/dist/engine/session/session-diff.d.ts +0 -11
- package/dist/engine/session/session-diff.js +0 -42
- package/dist/engine/session/session-merge.d.ts +0 -12
- package/dist/engine/session/session-merge.js +0 -55
- package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
- package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
- package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
- package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
- package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
- package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
- package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
- package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
- package/dist/engine/spec-changelog/core.d.ts +0 -16
- package/dist/engine/spec-changelog/core.js +0 -176
- package/dist/engine/spec-changelog/diff.d.ts +0 -18
- package/dist/engine/spec-changelog/diff.js +0 -121
- package/dist/engine/spec-changelog/index.d.ts +0 -3
- package/dist/engine/spec-changelog/index.js +0 -4
- package/dist/engine/trial-engine.d.ts +0 -5
- package/dist/engine/trial-engine.js +0 -14
- package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
- package/dist/engine/usage-tracker/rate-check.js +0 -18
- package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
- package/dist/engine/usage-tracker/rate-limiter.js +0 -73
- package/dist/engine/usage-tracker/trial.d.ts +0 -27
- package/dist/engine/usage-tracker/trial.js +0 -49
- package/dist/engine/webhook/event-handlers.d.ts +0 -25
- package/dist/engine/webhook/event-handlers.js +0 -89
- package/dist/engine/webhook/index.d.ts +0 -4
- package/dist/engine/webhook/index.js +0 -5
- package/dist/engine/webhook/server.d.ts +0 -12
- package/dist/engine/webhook/server.js +0 -249
- package/dist/engine/webhook/signature.d.ts +0 -16
- package/dist/engine/webhook/signature.js +0 -49
- package/dist/storage/license-store.d.ts +0 -6
- package/dist/storage/license-store.js +0 -63
- package/dist/storage/session-store.d.ts +0 -20
- package/dist/storage/session-store.js +0 -136
- package/dist/tools/activate-license.d.ts +0 -6
- package/dist/tools/activate-license.js +0 -132
- package/dist/tools/checkpoint-handler.d.ts +0 -3
- package/dist/tools/checkpoint-handler.js +0 -130
- package/dist/tools/export-session.d.ts +0 -3
- package/dist/tools/export-session.js +0 -90
- package/dist/tools/license-gate.d.ts +0 -18
- package/dist/tools/license-gate.js +0 -222
- package/dist/tools/license-status.d.ts +0 -3
- package/dist/tools/license-status.js +0 -93
- package/dist/tools/list-sessions.d.ts +0 -3
- package/dist/tools/list-sessions.js +0 -46
- package/dist/tools/planu-session-checkpoint.d.ts +0 -6
- package/dist/tools/planu-session-checkpoint.js +0 -42
- package/dist/tools/restore-session.d.ts +0 -3
- package/dist/tools/restore-session.js +0 -71
- package/dist/tools/spec-history.d.ts +0 -3
- package/dist/tools/spec-history.js +0 -59
- package/dist/tools/webhook.d.ts +0 -6
- package/dist/tools/webhook.js +0 -150
- package/dist/types/changelog.d.ts +0 -49
- package/dist/types/changelog.js +0 -3
- package/dist/types/licensing.d.ts +0 -109
- package/dist/types/licensing.js +0 -4
- package/dist/types/product-intelligence.d.ts +0 -60
- package/dist/types/product-intelligence.js +0 -3
- package/dist/types/session.d.ts +0 -84
- package/dist/types/session.js +0 -3
- package/dist/types/webhook.d.ts +0 -62
- package/dist/types/webhook.js +0 -4
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare function getInstallationId(): string;
|
|
2
|
-
export declare function getTrialStatus(_projectId?: string): null;
|
|
3
|
-
export declare function isTrialActive(_projectId?: string): boolean;
|
|
4
|
-
export declare function requestTrial(_projectId?: string): Promise<void>;
|
|
5
|
-
//# sourceMappingURL=trial-engine.d.ts.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// engine/trial-engine.ts — Trial stub (trial tools removed in SPEC-533)
|
|
2
|
-
export function getInstallationId() {
|
|
3
|
-
return 'n/a';
|
|
4
|
-
}
|
|
5
|
-
export function getTrialStatus(_projectId) {
|
|
6
|
-
return null;
|
|
7
|
-
}
|
|
8
|
-
export function isTrialActive(_projectId) {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
export async function requestTrial(_projectId) {
|
|
12
|
-
// No-op: trial tools removed
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=trial-engine.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { RateLimitResult } from '../../types/index.js';
|
|
2
|
-
/**
|
|
3
|
-
* Evaluates both daily limit and cooldown in a single call.
|
|
4
|
-
* Returns the first failing check, or an allowed result if both pass.
|
|
5
|
-
*/
|
|
6
|
-
export declare function evaluateRateLimit(callCount: number, maxCalls: number, lastCallAt: string | null, now: Date): RateLimitResult;
|
|
7
|
-
//# sourceMappingURL=rate-check.d.ts.map
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// engine/usage-tracker/rate-check.ts — Composed rate-limit evaluation (pure, no I/O).
|
|
2
|
-
import { checkDailyLimit, checkCooldown } from './rate-limiter.js';
|
|
3
|
-
/**
|
|
4
|
-
* Evaluates both daily limit and cooldown in a single call.
|
|
5
|
-
* Returns the first failing check, or an allowed result if both pass.
|
|
6
|
-
*/
|
|
7
|
-
export function evaluateRateLimit(callCount, maxCalls, lastCallAt, now) {
|
|
8
|
-
const daily = checkDailyLimit(callCount, maxCalls);
|
|
9
|
-
if (!daily.allowed) {
|
|
10
|
-
return daily;
|
|
11
|
-
}
|
|
12
|
-
const cooldown = checkCooldown(lastCallAt, now);
|
|
13
|
-
if (!cooldown.allowed) {
|
|
14
|
-
return cooldown;
|
|
15
|
-
}
|
|
16
|
-
return daily;
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=rate-check.js.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { RateLimitResult } from '../../types/index.js';
|
|
2
|
-
/** Minimum milliseconds required between consecutive tool calls. */
|
|
3
|
-
export declare const COOLDOWN_MS = 2000;
|
|
4
|
-
/**
|
|
5
|
-
* Checks whether the caller has exceeded the daily call limit.
|
|
6
|
-
* Returns an allowed result when maxCalls is -1 (unlimited).
|
|
7
|
-
*/
|
|
8
|
-
export declare function checkDailyLimit(callCount: number, maxCalls: number): RateLimitResult;
|
|
9
|
-
/**
|
|
10
|
-
* Checks whether enough time has passed since the last tool call.
|
|
11
|
-
* Passes when lastCallAt is null (no previous call recorded).
|
|
12
|
-
*/
|
|
13
|
-
export declare function checkCooldown(lastCallAt: string | null, now: Date): RateLimitResult;
|
|
14
|
-
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// engine/usage-tracker/rate-limiter.ts — Rate limiting logic (pure functions, no I/O).
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Constants
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
/** Minimum milliseconds required between consecutive tool calls. */
|
|
6
|
-
export const COOLDOWN_MS = 2000;
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
// Daily limit check
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
/**
|
|
11
|
-
* Checks whether the caller has exceeded the daily call limit.
|
|
12
|
-
* Returns an allowed result when maxCalls is -1 (unlimited).
|
|
13
|
-
*/
|
|
14
|
-
export function checkDailyLimit(callCount, maxCalls) {
|
|
15
|
-
if (maxCalls === -1) {
|
|
16
|
-
return {
|
|
17
|
-
allowed: true,
|
|
18
|
-
reason: null,
|
|
19
|
-
message: 'Unlimited calls available.',
|
|
20
|
-
remainingCalls: -1,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
const remaining = maxCalls - callCount;
|
|
24
|
-
if (remaining <= 0) {
|
|
25
|
-
return {
|
|
26
|
-
allowed: false,
|
|
27
|
-
reason: 'daily_limit',
|
|
28
|
-
message: `Daily call limit of ${String(maxCalls)} reached. Limit resets at midnight UTC.`,
|
|
29
|
-
remainingCalls: 0,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
allowed: true,
|
|
34
|
-
reason: null,
|
|
35
|
-
message: `${String(remaining)} of ${String(maxCalls)} daily calls remaining.`,
|
|
36
|
-
remainingCalls: remaining,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// Cooldown check
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
/**
|
|
43
|
-
* Checks whether enough time has passed since the last tool call.
|
|
44
|
-
* Passes when lastCallAt is null (no previous call recorded).
|
|
45
|
-
*/
|
|
46
|
-
export function checkCooldown(lastCallAt, now) {
|
|
47
|
-
if (lastCallAt === null) {
|
|
48
|
-
return {
|
|
49
|
-
allowed: true,
|
|
50
|
-
reason: null,
|
|
51
|
-
message: 'No previous call recorded.',
|
|
52
|
-
remainingCalls: -1,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
const lastCallMs = new Date(lastCallAt).getTime();
|
|
56
|
-
const elapsedMs = now.getTime() - lastCallMs;
|
|
57
|
-
if (elapsedMs < COOLDOWN_MS) {
|
|
58
|
-
const waitMs = COOLDOWN_MS - elapsedMs;
|
|
59
|
-
return {
|
|
60
|
-
allowed: false,
|
|
61
|
-
reason: 'cooldown',
|
|
62
|
-
message: `Rate limit: please wait ${String(waitMs)}ms before the next call.`,
|
|
63
|
-
remainingCalls: -1,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
allowed: true,
|
|
68
|
-
reason: null,
|
|
69
|
-
message: 'Cooldown period elapsed.',
|
|
70
|
-
remainingCalls: -1,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/** Number of days in the full trial period. */
|
|
2
|
-
export declare const TRIAL_DAYS = 30;
|
|
3
|
-
/**
|
|
4
|
-
* Returns the number of whole days elapsed since the given ISO 8601 timestamp.
|
|
5
|
-
*/
|
|
6
|
-
export declare function calculateDaysSinceFirstRun(firstRunAt: string): number;
|
|
7
|
-
/**
|
|
8
|
-
* Returns true if the installation is still within the 30-day trial period.
|
|
9
|
-
*/
|
|
10
|
-
export declare function isTrialActive(firstRunAt: string): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Returns the number of days remaining in the trial period.
|
|
13
|
-
* Returns 0 if the trial has already expired.
|
|
14
|
-
*/
|
|
15
|
-
export declare function trialDaysRemaining(firstRunAt: string): number;
|
|
16
|
-
/**
|
|
17
|
-
* Returns tool/spec/daily-call limits based on the current trial status.
|
|
18
|
-
*
|
|
19
|
-
* - Day 1–30 (trial active): { tools: 20, specs: 5, dailyCalls: 50 }
|
|
20
|
-
* - Day 31+ (trial expired): { tools: 10, specs: 3, dailyCalls: 30 }
|
|
21
|
-
*/
|
|
22
|
-
export declare function getTrialLimits(firstRunAt: string): {
|
|
23
|
-
tools: number;
|
|
24
|
-
specs: number;
|
|
25
|
-
dailyCalls: number;
|
|
26
|
-
};
|
|
27
|
-
//# sourceMappingURL=trial.d.ts.map
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// engine/usage-tracker/trial.ts — Trial period logic (pure functions, no I/O).
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Constants
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
/** Number of days in the full trial period. */
|
|
6
|
-
export const TRIAL_DAYS = 30;
|
|
7
|
-
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
// Trial calculations
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
/**
|
|
12
|
-
* Returns the number of whole days elapsed since the given ISO 8601 timestamp.
|
|
13
|
-
*/
|
|
14
|
-
export function calculateDaysSinceFirstRun(firstRunAt) {
|
|
15
|
-
const firstRunMs = new Date(firstRunAt).getTime();
|
|
16
|
-
const nowMs = Date.now();
|
|
17
|
-
const elapsedMs = nowMs - firstRunMs;
|
|
18
|
-
return Math.floor(elapsedMs / MS_PER_DAY);
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Returns true if the installation is still within the 30-day trial period.
|
|
22
|
-
*/
|
|
23
|
-
export function isTrialActive(firstRunAt) {
|
|
24
|
-
return calculateDaysSinceFirstRun(firstRunAt) < TRIAL_DAYS;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Returns the number of days remaining in the trial period.
|
|
28
|
-
* Returns 0 if the trial has already expired.
|
|
29
|
-
*/
|
|
30
|
-
export function trialDaysRemaining(firstRunAt) {
|
|
31
|
-
const elapsed = calculateDaysSinceFirstRun(firstRunAt);
|
|
32
|
-
return Math.max(0, TRIAL_DAYS - elapsed);
|
|
33
|
-
}
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
// Limit resolution
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
/**
|
|
38
|
-
* Returns tool/spec/daily-call limits based on the current trial status.
|
|
39
|
-
*
|
|
40
|
-
* - Day 1–30 (trial active): { tools: 20, specs: 5, dailyCalls: 50 }
|
|
41
|
-
* - Day 31+ (trial expired): { tools: 10, specs: 3, dailyCalls: 30 }
|
|
42
|
-
*/
|
|
43
|
-
export function getTrialLimits(firstRunAt) {
|
|
44
|
-
if (isTrialActive(firstRunAt)) {
|
|
45
|
-
return { tools: 20, specs: 5, dailyCalls: 50 };
|
|
46
|
-
}
|
|
47
|
-
return { tools: 10, specs: 3, dailyCalls: 30 };
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=trial.js.map
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { LemonSqueezyWebhookPayload, WebhookProcessResult } from '../../types/index.js';
|
|
2
|
-
/**
|
|
3
|
-
* Handles subscription_cancelled: the customer cancelled their subscription.
|
|
4
|
-
* The tier should be reverted to free when the subscription period ends.
|
|
5
|
-
*/
|
|
6
|
-
export declare function handleSubscriptionCancelled(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
|
|
7
|
-
/**
|
|
8
|
-
* Handles subscription_updated: plan tier may have changed (upgrade/downgrade).
|
|
9
|
-
*/
|
|
10
|
-
export declare function handleSubscriptionUpdated(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
|
|
11
|
-
/**
|
|
12
|
-
* Handles license_key_created: a new license key was issued (after purchase).
|
|
13
|
-
* This is informational — the user will activate the key via activate_license tool.
|
|
14
|
-
*/
|
|
15
|
-
export declare function handleLicenseKeyCreated(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
|
|
16
|
-
/**
|
|
17
|
-
* Returns a generic "acknowledged" result for unhandled but recognised events.
|
|
18
|
-
*/
|
|
19
|
-
export declare function handleUnknownEvent(eventType: string): WebhookProcessResult;
|
|
20
|
-
/**
|
|
21
|
-
* Dispatches a parsed webhook payload to the appropriate event handler.
|
|
22
|
-
* Unhandled but valid events are acknowledged with a 200 response.
|
|
23
|
-
*/
|
|
24
|
-
export declare function dispatchWebhookEvent(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
|
|
25
|
-
//# sourceMappingURL=event-handlers.d.ts.map
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
// engine/webhook/event-handlers.ts — Handles individual Lemon Squeezy webhook events.
|
|
2
|
-
// Each handler receives parsed payload and applies the corresponding business logic.
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// Individual event handlers
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
/**
|
|
7
|
-
* Handles subscription_cancelled: the customer cancelled their subscription.
|
|
8
|
-
* The tier should be reverted to free when the subscription period ends.
|
|
9
|
-
*/
|
|
10
|
-
export function handleSubscriptionCancelled(payload) {
|
|
11
|
-
const attrs = payload.data.attributes;
|
|
12
|
-
const endsAt = attrs.ends_at ?? 'unknown date';
|
|
13
|
-
const productName = attrs.product_name ?? 'Planu subscription';
|
|
14
|
-
return {
|
|
15
|
-
success: true,
|
|
16
|
-
eventType: 'subscription_cancelled',
|
|
17
|
-
statusCode: 200,
|
|
18
|
-
message: [
|
|
19
|
-
`Subscription cancellation recorded: ${productName}`,
|
|
20
|
-
`Access continues until: ${endsAt}`,
|
|
21
|
-
'Tier will revert to free upon expiry.',
|
|
22
|
-
].join(' | '),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Handles subscription_updated: plan tier may have changed (upgrade/downgrade).
|
|
27
|
-
*/
|
|
28
|
-
export function handleSubscriptionUpdated(payload) {
|
|
29
|
-
const attrs = payload.data.attributes;
|
|
30
|
-
const variantName = attrs.variant_name ?? 'unknown variant';
|
|
31
|
-
const status = attrs.status ?? 'unknown';
|
|
32
|
-
return {
|
|
33
|
-
success: true,
|
|
34
|
-
eventType: 'subscription_updated',
|
|
35
|
-
statusCode: 200,
|
|
36
|
-
message: [`Subscription updated: variant=${variantName}`, `status=${status}`].join(' | '),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Handles license_key_created: a new license key was issued (after purchase).
|
|
41
|
-
* This is informational — the user will activate the key via activate_license tool.
|
|
42
|
-
*/
|
|
43
|
-
export function handleLicenseKeyCreated(payload) {
|
|
44
|
-
const attrs = payload.data.attributes;
|
|
45
|
-
const productName = attrs.product_name ?? 'Planu';
|
|
46
|
-
const userEmail = attrs.user_email ?? 'unknown';
|
|
47
|
-
return {
|
|
48
|
-
success: true,
|
|
49
|
-
eventType: 'license_key_created',
|
|
50
|
-
statusCode: 200,
|
|
51
|
-
message: [
|
|
52
|
-
`License key created for: ${productName}`,
|
|
53
|
-
`customer=${userEmail}`,
|
|
54
|
-
'Key can be activated using activate_license tool.',
|
|
55
|
-
].join(' | '),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Returns a generic "acknowledged" result for unhandled but recognised events.
|
|
60
|
-
*/
|
|
61
|
-
export function handleUnknownEvent(eventType) {
|
|
62
|
-
return {
|
|
63
|
-
success: true,
|
|
64
|
-
eventType,
|
|
65
|
-
statusCode: 200,
|
|
66
|
-
message: `Event acknowledged (no handler): ${eventType}`,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
// Dispatcher
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
const HANDLERS = {
|
|
73
|
-
subscription_cancelled: handleSubscriptionCancelled,
|
|
74
|
-
subscription_updated: handleSubscriptionUpdated,
|
|
75
|
-
license_key_created: handleLicenseKeyCreated,
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Dispatches a parsed webhook payload to the appropriate event handler.
|
|
79
|
-
* Unhandled but valid events are acknowledged with a 200 response.
|
|
80
|
-
*/
|
|
81
|
-
export function dispatchWebhookEvent(payload) {
|
|
82
|
-
const eventType = payload.meta.event_name;
|
|
83
|
-
const handler = HANDLERS[eventType];
|
|
84
|
-
if (handler) {
|
|
85
|
-
return handler(payload);
|
|
86
|
-
}
|
|
87
|
-
return handleUnknownEvent(eventType);
|
|
88
|
-
}
|
|
89
|
-
//# sourceMappingURL=event-handlers.js.map
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { startWebhookServer, stopWebhookServer, getWebhookState, setWebhookSecret, } from './server.js';
|
|
2
|
-
export { validateSignature, extractSignatureHeader } from './signature.js';
|
|
3
|
-
export { dispatchWebhookEvent, handleSubscriptionCancelled, handleSubscriptionUpdated, handleLicenseKeyCreated, handleUnknownEvent, } from './event-handlers.js';
|
|
4
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// engine/webhook/index.ts — Barrel re-export for the webhook engine module.
|
|
2
|
-
export { startWebhookServer, stopWebhookServer, getWebhookState, setWebhookSecret, } from './server.js';
|
|
3
|
-
export { validateSignature, extractSignatureHeader } from './signature.js';
|
|
4
|
-
export { dispatchWebhookEvent, handleSubscriptionCancelled, handleSubscriptionUpdated, handleLicenseKeyCreated, handleUnknownEvent, } from './event-handlers.js';
|
|
5
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { WebhookServerState } from '../../types/index.js';
|
|
2
|
-
/** Returns the current webhook server state (immutable snapshot). */
|
|
3
|
-
export declare function getWebhookState(): WebhookServerState;
|
|
4
|
-
/** Replaces the webhook secret used for HMAC-SHA256 validation. */
|
|
5
|
-
export declare function setWebhookSecret(secret: string): void;
|
|
6
|
-
/** Starts the HTTP webhook server on the given port. Idempotent. */
|
|
7
|
-
export declare function startWebhookServer(port?: number): Promise<WebhookServerState>;
|
|
8
|
-
/** Stops the running webhook server gracefully. Idempotent. */
|
|
9
|
-
export declare function stopWebhookServer(): Promise<WebhookServerState>;
|
|
10
|
-
/** Reset replay protection state (for testing only). */
|
|
11
|
-
export declare function _resetReplayState(): void;
|
|
12
|
-
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
// engine/webhook/server.ts — Lightweight HTTP webhook receiver using node:http.
|
|
2
|
-
// No framework dependencies — only built-in Node.js modules.
|
|
3
|
-
import { createServer } from 'node:http';
|
|
4
|
-
import { randomUUID, createHash } from 'node:crypto';
|
|
5
|
-
import { validateSignature, extractSignatureHeader } from './signature.js';
|
|
6
|
-
import { dispatchWebhookEvent } from './event-handlers.js';
|
|
7
|
-
// Constants
|
|
8
|
-
const DEFAULT_PORT = 2358;
|
|
9
|
-
const MAX_RECENT_EVENTS = 20;
|
|
10
|
-
const MAX_BODY_SIZE = 1024 * 1024; // 1 MB
|
|
11
|
-
const NONCE_CACHE_SIZE = 1000;
|
|
12
|
-
const MAX_TIMESTAMP_AGE_MS = 5 * 60 * 1000; // 5 minutes
|
|
13
|
-
const RATE_LIMIT_WINDOW_MS = 60 * 1000;
|
|
14
|
-
const RATE_LIMIT_MAX = 10;
|
|
15
|
-
// Module state
|
|
16
|
-
let activeServer = null;
|
|
17
|
-
let serverState = makeIdleState();
|
|
18
|
-
let webhookSecret = '';
|
|
19
|
-
const recentNonces = new Set();
|
|
20
|
-
const nonceQueue = [];
|
|
21
|
-
const rateLimitMap = new Map();
|
|
22
|
-
// Public API
|
|
23
|
-
/** Returns the current webhook server state (immutable snapshot). */
|
|
24
|
-
export function getWebhookState() {
|
|
25
|
-
return serverState;
|
|
26
|
-
}
|
|
27
|
-
/** Replaces the webhook secret used for HMAC-SHA256 validation. */
|
|
28
|
-
export function setWebhookSecret(secret) {
|
|
29
|
-
webhookSecret = secret;
|
|
30
|
-
}
|
|
31
|
-
/** Starts the HTTP webhook server on the given port. Idempotent. */
|
|
32
|
-
export async function startWebhookServer(port = DEFAULT_PORT) {
|
|
33
|
-
if (activeServer !== null) {
|
|
34
|
-
return serverState;
|
|
35
|
-
}
|
|
36
|
-
return new Promise((resolve, reject) => {
|
|
37
|
-
const server = createServer(handleRequest);
|
|
38
|
-
server.on('error', (err) => {
|
|
39
|
-
reject(err);
|
|
40
|
-
});
|
|
41
|
-
server.listen(port, () => {
|
|
42
|
-
activeServer = server;
|
|
43
|
-
serverState = {
|
|
44
|
-
running: true,
|
|
45
|
-
port,
|
|
46
|
-
startedAt: new Date().toISOString(),
|
|
47
|
-
eventsProcessed: 0,
|
|
48
|
-
recentEvents: [],
|
|
49
|
-
};
|
|
50
|
-
if (!webhookSecret) {
|
|
51
|
-
console.warn('[Planu] Warning: Webhook server started without a secret. All incoming requests will be accepted without signature verification. Set a secret via configure_webhook.');
|
|
52
|
-
}
|
|
53
|
-
resolve(serverState);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
/** Stops the running webhook server gracefully. Idempotent. */
|
|
58
|
-
export async function stopWebhookServer() {
|
|
59
|
-
if (activeServer === null) {
|
|
60
|
-
serverState = makeIdleState();
|
|
61
|
-
return serverState;
|
|
62
|
-
}
|
|
63
|
-
const server = activeServer;
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
server.close((err) => {
|
|
66
|
-
/* v8 ignore start */
|
|
67
|
-
if (err) {
|
|
68
|
-
reject(err);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
/* v8 ignore stop */
|
|
72
|
-
activeServer = null;
|
|
73
|
-
serverState = makeIdleState();
|
|
74
|
-
resolve(serverState);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
// HTTP request handler
|
|
79
|
-
function handleRequest(req, res) {
|
|
80
|
-
if (req.method !== 'POST') {
|
|
81
|
-
res.writeHead(405, { 'Content-Type': 'text/plain' });
|
|
82
|
-
res.end('Method Not Allowed');
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
collectBody(req)
|
|
86
|
-
.then((rawBody) => {
|
|
87
|
-
processWebhookRequest(rawBody, req.headers, res);
|
|
88
|
-
})
|
|
89
|
-
.catch(() => {
|
|
90
|
-
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
91
|
-
res.end('Bad Request');
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
function collectBody(req) {
|
|
95
|
-
return new Promise((resolve, reject) => {
|
|
96
|
-
const chunks = [];
|
|
97
|
-
let totalSize = 0;
|
|
98
|
-
req.on('data', (chunk) => {
|
|
99
|
-
totalSize += chunk.length;
|
|
100
|
-
if (totalSize > MAX_BODY_SIZE) {
|
|
101
|
-
reject(new Error('Payload too large'));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
chunks.push(chunk);
|
|
105
|
-
});
|
|
106
|
-
req.on('end', () => {
|
|
107
|
-
resolve(Buffer.concat(chunks));
|
|
108
|
-
});
|
|
109
|
-
req.on('error', reject);
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
// Replay & rate-limit protection (SPEC-094 AC-7)
|
|
113
|
-
function isReplayAttack(headers, bodyStr) {
|
|
114
|
-
const tsHeader = headers['x-webhook-timestamp'] ?? headers['X-Webhook-Timestamp'];
|
|
115
|
-
const timestamp = typeof tsHeader === 'string' ? tsHeader : undefined;
|
|
116
|
-
if (timestamp) {
|
|
117
|
-
const age = Date.now() - new Date(timestamp).getTime();
|
|
118
|
-
if (age > MAX_TIMESTAMP_AGE_MS || age < -MAX_TIMESTAMP_AGE_MS) {
|
|
119
|
-
return 'Webhook timestamp too old or in the future';
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const nonce = extractNonce(headers, bodyStr);
|
|
123
|
-
if (nonce && recentNonces.has(nonce)) {
|
|
124
|
-
return 'Duplicate webhook (replay detected)';
|
|
125
|
-
}
|
|
126
|
-
if (nonce) {
|
|
127
|
-
trackNonce(nonce);
|
|
128
|
-
}
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
function extractNonce(headers, bodyStr) {
|
|
132
|
-
const idHeader = headers['x-webhook-id'] ?? headers['X-Webhook-Id'];
|
|
133
|
-
if (typeof idHeader === 'string') {
|
|
134
|
-
return idHeader;
|
|
135
|
-
}
|
|
136
|
-
return createHash('sha256').update(bodyStr).digest('hex').slice(0, 32);
|
|
137
|
-
}
|
|
138
|
-
function trackNonce(nonce) {
|
|
139
|
-
recentNonces.add(nonce);
|
|
140
|
-
nonceQueue.push(nonce);
|
|
141
|
-
while (nonceQueue.length > NONCE_CACHE_SIZE) {
|
|
142
|
-
const old = nonceQueue.shift();
|
|
143
|
-
if (old) {
|
|
144
|
-
recentNonces.delete(old);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
function isRateLimited(source) {
|
|
149
|
-
const now = Date.now();
|
|
150
|
-
const entry = rateLimitMap.get(source);
|
|
151
|
-
if (!entry || now - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
|
|
152
|
-
rateLimitMap.set(source, { count: 1, windowStart: now });
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
entry.count++;
|
|
156
|
-
return entry.count > RATE_LIMIT_MAX;
|
|
157
|
-
}
|
|
158
|
-
/** Reset replay protection state (for testing only). */
|
|
159
|
-
export function _resetReplayState() {
|
|
160
|
-
recentNonces.clear();
|
|
161
|
-
nonceQueue.length = 0;
|
|
162
|
-
rateLimitMap.clear();
|
|
163
|
-
}
|
|
164
|
-
function processWebhookRequest(rawBody, headers, res) {
|
|
165
|
-
// Rate limiting
|
|
166
|
-
const source = String(headers['x-forwarded-for'] ?? headers['x-real-ip'] ?? 'unknown');
|
|
167
|
-
if (isRateLimited(source)) {
|
|
168
|
-
res.writeHead(429, { 'Content-Type': 'text/plain' });
|
|
169
|
-
res.end('Too Many Requests');
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
// Replay protection
|
|
173
|
-
const replayReason = isReplayAttack(headers, rawBody.toString('utf8'));
|
|
174
|
-
if (replayReason) {
|
|
175
|
-
recordEvent('replay_rejected', false, replayReason, '');
|
|
176
|
-
res.writeHead(409, { 'Content-Type': 'text/plain' });
|
|
177
|
-
res.end(replayReason);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
// Signature validation (only if a secret is configured)
|
|
181
|
-
if (webhookSecret) {
|
|
182
|
-
const sig = extractSignatureHeader(headers);
|
|
183
|
-
if (!validateSignature(rawBody, sig, webhookSecret)) {
|
|
184
|
-
recordEvent('signature_invalid', false, 'Signature validation failed', '');
|
|
185
|
-
res.writeHead(401, { 'Content-Type': 'text/plain' });
|
|
186
|
-
res.end('Unauthorized');
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
// Parse JSON body
|
|
191
|
-
let payload;
|
|
192
|
-
try {
|
|
193
|
-
payload = JSON.parse(rawBody.toString('utf8'));
|
|
194
|
-
}
|
|
195
|
-
catch {
|
|
196
|
-
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
197
|
-
res.end('Invalid JSON');
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (!payload.meta?.event_name) {
|
|
201
|
-
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
202
|
-
res.end('Invalid payload: missing meta.event_name');
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
// Dispatch event
|
|
206
|
-
const eventType = payload.meta.event_name;
|
|
207
|
-
try {
|
|
208
|
-
const result = dispatchWebhookEvent(payload);
|
|
209
|
-
recordEvent(eventType, result.success, result.message, result.eventType);
|
|
210
|
-
res.writeHead(result.statusCode, { 'Content-Type': 'application/json' });
|
|
211
|
-
res.end(JSON.stringify({ ok: true, message: result.message }));
|
|
212
|
-
/* v8 ignore start */
|
|
213
|
-
}
|
|
214
|
-
catch (err) {
|
|
215
|
-
const errMsg = err instanceof Error ? err.message : 'Unknown error';
|
|
216
|
-
recordEvent(eventType, false, errMsg, eventType);
|
|
217
|
-
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
218
|
-
res.end('Internal Server Error');
|
|
219
|
-
}
|
|
220
|
-
/* v8 ignore stop */
|
|
221
|
-
}
|
|
222
|
-
// Event recording
|
|
223
|
-
function recordEvent(_eventType, processed, summary, resolvedType) {
|
|
224
|
-
const record = {
|
|
225
|
-
id: randomUUID(),
|
|
226
|
-
eventType: resolvedType,
|
|
227
|
-
receivedAt: new Date().toISOString(),
|
|
228
|
-
processed,
|
|
229
|
-
summary,
|
|
230
|
-
...(processed ? {} : { error: summary }),
|
|
231
|
-
};
|
|
232
|
-
const recentEvents = [record, ...serverState.recentEvents].slice(0, MAX_RECENT_EVENTS);
|
|
233
|
-
serverState = {
|
|
234
|
-
...serverState,
|
|
235
|
-
eventsProcessed: serverState.eventsProcessed + 1,
|
|
236
|
-
recentEvents,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
// Helpers
|
|
240
|
-
function makeIdleState() {
|
|
241
|
-
return {
|
|
242
|
-
running: false,
|
|
243
|
-
port: DEFAULT_PORT,
|
|
244
|
-
startedAt: null,
|
|
245
|
-
eventsProcessed: 0,
|
|
246
|
-
recentEvents: [],
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
//# sourceMappingURL=server.js.map
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validates an HMAC-SHA256 signature from a Lemon Squeezy webhook request.
|
|
3
|
-
* Uses timing-safe comparison to prevent timing attacks.
|
|
4
|
-
*
|
|
5
|
-
* @param rawBody - The raw request body bytes (NOT parsed JSON)
|
|
6
|
-
* @param signatureHeader - The value of the X-Signature header
|
|
7
|
-
* @param secret - The webhook secret configured in Lemon Squeezy dashboard
|
|
8
|
-
* @returns true if signature is valid, false otherwise
|
|
9
|
-
*/
|
|
10
|
-
export declare function validateSignature(rawBody: Buffer, signatureHeader: string, secret: string): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Extracts the signature header value from a map of HTTP headers.
|
|
13
|
-
* Header names are case-insensitive in HTTP/1.1.
|
|
14
|
-
*/
|
|
15
|
-
export declare function extractSignatureHeader(headers: Record<string, string | string[] | undefined>): string;
|
|
16
|
-
//# sourceMappingURL=signature.d.ts.map
|