approval-md 0.2.0 → 0.4.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/README.md +85 -877
- package/SPEC.md +150 -19
- package/cli.js +66 -7
- package/dist/src/adapters/smtp.d.ts +18 -0
- package/dist/src/adapters/smtp.js +24 -3
- package/dist/src/adapters/smtp.js.map +1 -1
- package/dist/src/channels/contract.d.ts +53 -1
- package/dist/src/channels/contract.js +304 -7
- package/dist/src/channels/contract.js.map +1 -1
- package/dist/src/channels/relay-server.d.ts +90 -0
- package/dist/src/channels/relay-server.js +295 -0
- package/dist/src/channels/relay-server.js.map +1 -0
- package/dist/src/channels/relay.d.ts +273 -0
- package/dist/src/channels/relay.js +564 -0
- package/dist/src/channels/relay.js.map +1 -0
- package/dist/src/channels/tagging.js +6 -1
- package/dist/src/channels/tagging.js.map +1 -1
- package/dist/src/channels/telegram-webhook.d.ts +273 -0
- package/dist/src/channels/telegram-webhook.js +536 -0
- package/dist/src/channels/telegram-webhook.js.map +1 -0
- package/dist/src/channels/telegram.d.ts +394 -12
- package/dist/src/channels/telegram.js +621 -68
- package/dist/src/channels/telegram.js.map +1 -1
- package/dist/src/channels/web.d.ts +9 -0
- package/dist/src/channels/web.js +17 -0
- package/dist/src/channels/web.js.map +1 -1
- package/dist/src/cli/amend.js +564 -34
- package/dist/src/cli/amend.js.map +1 -1
- package/dist/src/cli/attest.d.ts +9 -0
- package/dist/src/cli/attest.js +177 -13
- package/dist/src/cli/attest.js.map +1 -1
- package/dist/src/cli/channel-relay.d.ts +108 -0
- package/dist/src/cli/channel-relay.js +334 -0
- package/dist/src/cli/channel-relay.js.map +1 -0
- package/dist/src/cli/channel-telegram-webhook.d.ts +273 -0
- package/dist/src/cli/channel-telegram-webhook.js +709 -0
- package/dist/src/cli/channel-telegram-webhook.js.map +1 -0
- package/dist/src/cli/channel-telegram.d.ts +347 -28
- package/dist/src/cli/channel-telegram.js +763 -28
- package/dist/src/cli/channel-telegram.js.map +1 -1
- package/dist/src/cli/channel.d.ts +10 -1
- package/dist/src/cli/channel.js +14 -1
- package/dist/src/cli/channel.js.map +1 -1
- package/dist/src/cli/codex-bridge.d.ts +819 -0
- package/dist/src/cli/codex-bridge.js +1607 -0
- package/dist/src/cli/codex-bridge.js.map +1 -0
- package/dist/src/cli/codex.d.ts +1 -1
- package/dist/src/cli/codex.js +304 -7
- package/dist/src/cli/codex.js.map +1 -1
- package/dist/src/cli/daemon.js +41 -6
- package/dist/src/cli/daemon.js.map +1 -1
- package/dist/src/cli/doctor.d.ts +63 -0
- package/dist/src/cli/doctor.js +1322 -122
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/execute.d.ts +17 -1
- package/dist/src/cli/execute.js +366 -22
- package/dist/src/cli/execute.js.map +1 -1
- package/dist/src/cli/exit-codes.d.ts +12 -0
- package/dist/src/cli/exit-codes.js +13 -0
- package/dist/src/cli/exit-codes.js.map +1 -1
- package/dist/src/cli/gate.d.ts +2 -0
- package/dist/src/cli/gate.js +233 -2
- package/dist/src/cli/gate.js.map +1 -1
- package/dist/src/cli/help.d.ts +14 -2
- package/dist/src/cli/help.js +395 -82
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook-codex.d.ts +49 -1
- package/dist/src/cli/hook-codex.js +60 -1
- package/dist/src/cli/hook-codex.js.map +1 -1
- package/dist/src/cli/hook.d.ts +828 -4
- package/dist/src/cli/hook.js +2972 -142
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/import.js +1 -1
- package/dist/src/cli/import.js.map +1 -1
- package/dist/src/cli/init.js +16 -7
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/instructions.js +24 -3
- package/dist/src/cli/instructions.js.map +1 -1
- package/dist/src/cli/log-anchor.d.ts +55 -0
- package/dist/src/cli/log-anchor.js +199 -60
- package/dist/src/cli/log-anchor.js.map +1 -1
- package/dist/src/cli/main.d.ts +0 -12
- package/dist/src/cli/main.js +56 -3
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/muse.d.ts +2 -0
- package/dist/src/cli/muse.js +62 -0
- package/dist/src/cli/muse.js.map +1 -0
- package/dist/src/cli/payload.js +79 -1
- package/dist/src/cli/payload.js.map +1 -1
- package/dist/src/cli/policy-apply.d.ts +195 -0
- package/dist/src/cli/policy-apply.js +573 -0
- package/dist/src/cli/policy-apply.js.map +1 -0
- package/dist/src/cli/policy.js +14 -1
- package/dist/src/cli/policy.js.map +1 -1
- package/dist/src/cli/preflight.d.ts +151 -13
- package/dist/src/cli/preflight.js +398 -41
- package/dist/src/cli/preflight.js.map +1 -1
- package/dist/src/cli/sandbox.js +17 -1
- package/dist/src/cli/sandbox.js.map +1 -1
- package/dist/src/cli/scaffold.d.ts +1 -1
- package/dist/src/cli/scaffold.js +7 -1
- package/dist/src/cli/scaffold.js.map +1 -1
- package/dist/src/cli/serve.d.ts +53 -0
- package/dist/src/cli/serve.js +270 -0
- package/dist/src/cli/serve.js.map +1 -0
- package/dist/src/cli/setup-channel.d.ts +9 -0
- package/dist/src/cli/setup-channel.js +28 -1
- package/dist/src/cli/setup-channel.js.map +1 -1
- package/dist/src/cli/setup-common.d.ts +3 -1
- package/dist/src/cli/setup-common.js +3 -2
- package/dist/src/cli/setup-common.js.map +1 -1
- package/dist/src/cli/setup.d.ts +2 -0
- package/dist/src/cli/setup.js +94 -2
- package/dist/src/cli/setup.js.map +1 -1
- package/dist/src/cli/up.js +134 -51
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/values.js +3 -4
- package/dist/src/cli/values.js.map +1 -1
- package/dist/src/cli/verb-registry.d.ts +2 -0
- package/dist/src/cli/verb-registry.js +510 -47
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +2 -2
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/codex/broker.d.ts +229 -0
- package/dist/src/codex/broker.js +548 -0
- package/dist/src/codex/broker.js.map +1 -0
- package/dist/src/codex/runner.d.ts +178 -0
- package/dist/src/codex/runner.js +231 -0
- package/dist/src/codex/runner.js.map +1 -0
- package/dist/src/codex/serve.d.ts +56 -0
- package/dist/src/codex/serve.js +98 -0
- package/dist/src/codex/serve.js.map +1 -0
- package/dist/src/codex/workspace-commit.d.ts +219 -0
- package/dist/src/codex/workspace-commit.js +549 -0
- package/dist/src/codex/workspace-commit.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +51 -0
- package/dist/src/core/advance-cycle.js +66 -2
- package/dist/src/core/advance-cycle.js.map +1 -1
- package/dist/src/core/agents-md.d.ts +20 -18
- package/dist/src/core/agents-md.js +33 -31
- package/dist/src/core/agents-md.js.map +1 -1
- package/dist/src/core/attest-bootstrap.d.ts +95 -0
- package/dist/src/core/attest-bootstrap.js +135 -0
- package/dist/src/core/attest-bootstrap.js.map +1 -0
- package/dist/src/core/attest.d.ts +234 -2
- package/dist/src/core/attest.js +342 -7
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +73 -3
- package/dist/src/core/audit.js +65 -5
- package/dist/src/core/audit.js.map +1 -1
- package/dist/src/core/channel-lease.d.ts +322 -0
- package/dist/src/core/channel-lease.js +663 -0
- package/dist/src/core/channel-lease.js.map +1 -0
- package/dist/src/core/channel-owner.d.ts +213 -0
- package/dist/src/core/channel-owner.js +358 -0
- package/dist/src/core/channel-owner.js.map +1 -0
- package/dist/src/core/command-class.d.ts +205 -0
- package/dist/src/core/command-class.js +1433 -28
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/commit-guard.d.ts +272 -0
- package/dist/src/core/commit-guard.js +424 -0
- package/dist/src/core/commit-guard.js.map +1 -0
- package/dist/src/core/daemon-actor.d.ts +45 -0
- package/dist/src/core/daemon-actor.js +54 -0
- package/dist/src/core/daemon-actor.js.map +1 -0
- package/dist/src/core/daemon-host.d.ts +178 -0
- package/dist/src/core/daemon-host.js +228 -0
- package/dist/src/core/daemon-host.js.map +1 -0
- package/dist/src/core/daemon-identity.d.ts +238 -0
- package/dist/src/core/daemon-identity.js +252 -0
- package/dist/src/core/daemon-identity.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +109 -8
- package/dist/src/core/dark-session.js +266 -82
- package/dist/src/core/dark-session.js.map +1 -1
- package/dist/src/core/decision-refusal.d.ts +23 -2
- package/dist/src/core/decision-refusal.js +24 -2
- package/dist/src/core/decision-refusal.js.map +1 -1
- package/dist/src/core/env-file.d.ts +5 -0
- package/dist/src/core/env-file.js +60 -1
- package/dist/src/core/env-file.js.map +1 -1
- package/dist/src/core/execute.d.ts +15 -2
- package/dist/src/core/execute.js +15 -2
- package/dist/src/core/execute.js.map +1 -1
- package/dist/src/core/gate.d.ts +392 -6
- package/dist/src/core/gate.js +852 -24
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/gesture-refusal.d.ts +166 -0
- package/dist/src/core/gesture-refusal.js +188 -0
- package/dist/src/core/gesture-refusal.js.map +1 -0
- package/dist/src/core/harness-version.d.ts +128 -4
- package/dist/src/core/harness-version.js +181 -12
- package/dist/src/core/harness-version.js.map +1 -1
- package/dist/src/core/harness-wait.d.ts +82 -3
- package/dist/src/core/harness-wait.js +89 -3
- package/dist/src/core/harness-wait.js.map +1 -1
- package/dist/src/core/instance.d.ts +59 -2
- package/dist/src/core/instance.js +113 -0
- package/dist/src/core/instance.js.map +1 -1
- package/dist/src/core/log-subscribe.d.ts +21 -0
- package/dist/src/core/log-subscribe.js +16 -6
- package/dist/src/core/log-subscribe.js.map +1 -1
- package/dist/src/core/log-write-layer.d.ts +55 -0
- package/dist/src/core/log-write-layer.js +91 -0
- package/dist/src/core/log-write-layer.js.map +1 -0
- package/dist/src/core/log.d.ts +89 -22
- package/dist/src/core/log.js +197 -19
- package/dist/src/core/log.js.map +1 -1
- package/dist/src/core/payload-census.d.ts +51 -0
- package/dist/src/core/payload-census.js +125 -2
- package/dist/src/core/payload-census.js.map +1 -1
- package/dist/src/core/payload-store.d.ts +31 -0
- package/dist/src/core/payload-store.js +113 -8
- package/dist/src/core/payload-store.js.map +1 -1
- package/dist/src/core/payload.d.ts +18 -3
- package/dist/src/core/payload.js +20 -4
- package/dist/src/core/payload.js.map +1 -1
- package/dist/src/core/policy-diff.d.ts +10 -0
- package/dist/src/core/policy-diff.js +10 -2
- package/dist/src/core/policy-diff.js.map +1 -1
- package/dist/src/core/policy-explain.d.ts +17 -1
- package/dist/src/core/policy-explain.js +48 -1
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +65 -1
- package/dist/src/core/policy-load.js +21 -3
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +81 -0
- package/dist/src/core/policy-match.js +87 -0
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +75 -0
- package/dist/src/core/policy-proposal.js +110 -4
- package/dist/src/core/policy-proposal.js.map +1 -1
- package/dist/src/core/protected-path-guard.d.ts +117 -4
- package/dist/src/core/protected-path-guard.js +362 -48
- package/dist/src/core/protected-path-guard.js.map +1 -1
- package/dist/src/core/question-preempted.d.ts +141 -0
- package/dist/src/core/question-preempted.js +152 -0
- package/dist/src/core/question-preempted.js.map +1 -0
- package/dist/src/core/read-scope.d.ts +182 -0
- package/dist/src/core/read-scope.js +256 -0
- package/dist/src/core/read-scope.js.map +1 -0
- package/dist/src/core/run-payload.d.ts +160 -0
- package/dist/src/core/run-payload.js +304 -0
- package/dist/src/core/run-payload.js.map +1 -0
- package/dist/src/core/sandbox.d.ts +81 -0
- package/dist/src/core/sandbox.js +190 -1
- package/dist/src/core/sandbox.js.map +1 -1
- package/dist/src/core/sender-identity.d.ts +501 -0
- package/dist/src/core/sender-identity.js +609 -0
- package/dist/src/core/sender-identity.js.map +1 -0
- package/dist/src/core/shlex.d.ts +102 -0
- package/dist/src/core/shlex.js +159 -0
- package/dist/src/core/shlex.js.map +1 -0
- package/dist/src/core/state.d.ts +52 -1
- package/dist/src/core/state.js +52 -6
- package/dist/src/core/state.js.map +1 -1
- package/dist/src/core/telegram-config.d.ts +79 -0
- package/dist/src/core/telegram-config.js +108 -0
- package/dist/src/core/telegram-config.js.map +1 -1
- package/dist/src/core/values.d.ts +18 -8
- package/dist/src/core/values.js +36 -1
- package/dist/src/core/values.js.map +1 -1
- package/dist/src/core/verify.d.ts +23 -1
- package/dist/src/core/verify.js +20 -2
- package/dist/src/core/verify.js.map +1 -1
- package/dist/src/daemon/advance.d.ts +10 -0
- package/dist/src/daemon/advance.js +25 -4
- package/dist/src/daemon/advance.js.map +1 -1
- package/dist/src/daemon/audit.d.ts +80 -5
- package/dist/src/daemon/audit.js +126 -6
- package/dist/src/daemon/audit.js.map +1 -1
- package/dist/src/daemon/daemon.d.ts +174 -2
- package/dist/src/daemon/daemon.js +307 -7
- package/dist/src/daemon/daemon.js.map +1 -1
- package/dist/src/daemon/git-evidence.d.ts +2 -2
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/daemon/projection.d.ts +13 -2
- package/dist/src/daemon/projection.js +39 -6
- package/dist/src/daemon/projection.js.map +1 -1
- package/dist/src/mcp/server.d.ts +39 -3
- package/dist/src/mcp/server.js +30 -3
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/muse/server.d.ts +16 -0
- package/dist/src/muse/server.js +238 -0
- package/dist/src/muse/server.js.map +1 -0
- package/dist/src/serve/archive.d.ts +158 -0
- package/dist/src/serve/archive.js +354 -0
- package/dist/src/serve/archive.js.map +1 -0
- package/dist/src/serve/arguments.d.ts +93 -0
- package/dist/src/serve/arguments.js +228 -0
- package/dist/src/serve/arguments.js.map +1 -0
- package/dist/src/serve/credentials.d.ts +91 -0
- package/dist/src/serve/credentials.js +143 -0
- package/dist/src/serve/credentials.js.map +1 -0
- package/dist/src/serve/follow.d.ts +86 -0
- package/dist/src/serve/follow.js +101 -0
- package/dist/src/serve/follow.js.map +1 -0
- package/dist/src/serve/hook-thread.d.ts +134 -0
- package/dist/src/serve/hook-thread.js +333 -0
- package/dist/src/serve/hook-thread.js.map +1 -0
- package/dist/src/serve/hook-worker.d.ts +134 -0
- package/dist/src/serve/hook-worker.js +173 -0
- package/dist/src/serve/hook-worker.js.map +1 -0
- package/dist/src/serve/server.d.ts +412 -0
- package/dist/src/serve/server.js +1251 -0
- package/dist/src/serve/server.js.map +1 -0
- package/docs/README-extended.md +766 -0
- package/docs/cli-reference.md +2563 -73
- package/docs/codex-enforced-session.md +75 -2
- package/docs/codex-workspace-broker.md +118 -0
- package/package.json +6 -2
- package/schema/event.schema.json +595 -9
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-false.json +20 -0
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-raw-id.json +20 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-human-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-no-actor-no-sender.json +15 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-unknown-gesture.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-no-question-id.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-unknown-source.json +15 -0
- package/schema/fixtures/event/invalid/daemon-id-malformed.json +15 -0
- package/schema/fixtures/event/invalid/execution-started-truncated-policy-sha256.json +18 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-missing-path.json +13 -0
- package/schema/fixtures/event/invalid/harness-cap-at-margin.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-fractional.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-negative.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-string.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-without-harness-execution.json +16 -0
- package/schema/fixtures/event/invalid/harness-cap-zero.json +16 -0
- package/schema/fixtures/event/valid/approval-granted-sender-hashed.json +20 -0
- package/schema/fixtures/event/valid/approval-requested-harness-cap.json +18 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-review-note.json +21 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-sender-key-unavailable.json +19 -0
- package/schema/fixtures/event/valid/audit-gesture-refused.json +19 -0
- package/schema/fixtures/event/valid/audit-question-preempted-no-verdict.json +16 -0
- package/schema/fixtures/event/valid/audit-question-preempted.json +20 -0
- package/schema/fixtures/event/valid/daemon-identity-declared.json +17 -0
- package/schema/fixtures/event/valid/daemon-identity.json +15 -0
- package/schema/fixtures/event/valid/execution-started-policy-sha256.json +18 -0
- package/schema/fixtures/event/valid/gate-path-signed-off.json +14 -0
- package/schema/fixtures/event/valid/harness-kind-claude-code.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-codex.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-cursor.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-grok.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-hermes.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-muse.json +23 -0
- package/schema/fixtures/policy/invalid/daemons-malformed-id.json +10 -0
- package/schema/fixtures/policy/invalid/senders-half-keyed.json +20 -0
- package/schema/fixtures/policy/valid/canonical.json +1 -1
- package/schema/fixtures/policy/valid/daemons-allowlist.json +19 -0
- package/schema/fixtures/policy/valid/senders-keyed.json +24 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-agent-may-request.md +21 -0
- package/schema/fixtures/policy-md/valid/agent-may-request.md +24 -0
- package/schema/fixtures/policy-md/valid/canonical.md +1 -1
- package/schema/fixtures/policy-md/valid/with-values.md +5 -7
- package/schema/fixtures/values/invalid/class-shaped.json +1 -1
- package/schema/fixtures/values/invalid/duplicate-entry.json +1 -1
- package/schema/fixtures/values/invalid/non-string-item.json +1 -1
- package/schema/fixtures/values/invalid/over-cap.json +1 -1
- package/schema/fixtures/values/invalid/unknown-key.json +1 -1
- package/schema/fixtures/values/invalid/version-float.json +1 -0
- package/schema/fixtures/values/invalid/version-integer.json +1 -0
- package/schema/fixtures/values/invalid/version-wrong-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +2 -3
- package/schema/fixtures/values/valid/full.json +5 -7
- package/schema/fixtures/values/valid/minimal.json +1 -1
- package/schema/fixtures/values-md/invalid/schema-invalid.md +5 -3
- package/schema/fixtures/values-md/invalid/two-blocks.md +3 -3
- package/schema/fixtures/values-md/invalid/unterminated.md +2 -2
- package/schema/fixtures/values-md/invalid/version-1.md +69 -0
- package/schema/fixtures/values-md/invalid/version-unquoted.md +64 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +2 -2
- package/schema/fixtures/values-md/valid/absent.md +1 -1
- package/schema/fixtures/values-md/valid/with-values.md +5 -7
- package/schema/policy.schema.json +100 -4
- package/schema/values.schema.json +7 -11
- package/schema/fixtures/values/invalid/version-string.json +0 -1
|
@@ -34,22 +34,59 @@
|
|
|
34
34
|
* notify, long-poll, callbacks, failure modes — against a local mock Bot API
|
|
35
35
|
* server and never touches the real network.
|
|
36
36
|
*
|
|
37
|
+
* ## Two transports, one update path (APRV-424)
|
|
38
|
+
*
|
|
39
|
+
* An update reaches this channel either because it long-polled for it
|
|
40
|
+
* ({@link TelegramChannel.pollOnce}) or because Telegram posted it to a URL the
|
|
41
|
+
* runtime registered ({@link TelegramChannel.deliverUpdate}, fed by
|
|
42
|
+
* `channels/telegram-webhook.ts`). That is the WHOLE of the difference. Both
|
|
43
|
+
* entry points hand the update to the same {@link TelegramChannel.handleUpdate}
|
|
44
|
+
* and therefore to the same chat check, the same `senderOf`, the same
|
|
45
|
+
* resolution ladder, the same `onDecision` handler and the same
|
|
46
|
+
* annotate-after-decision edit; a decision does not know which door it came
|
|
47
|
+
* through, and there is no second copy of any of it to drift.
|
|
48
|
+
*
|
|
49
|
+
* The two are mutually exclusive per bot, and the Bot API says so first:
|
|
50
|
+
* `getUpdates` is refused outright while a webhook is set.
|
|
51
|
+
* {@link TelegramChannel.claimTransport} refuses the in-process form of the
|
|
52
|
+
* mistake, and the verbs above ask `getWebhookInfo` and the ownership registry
|
|
53
|
+
* about the cross-process one.
|
|
54
|
+
*
|
|
37
55
|
* ## Config-declared identity — SPEC.md §11
|
|
38
56
|
*
|
|
39
57
|
* > Human identity in v0.1 is config-declared (an environment variable or
|
|
40
58
|
* > flag); the trust boundary is the local machine, and anyone who can set that
|
|
41
59
|
* > configuration and write to the log is inside it.
|
|
42
60
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
61
|
+
* What this channel authenticates, exactly: that the callback arrived **from
|
|
62
|
+
* the configured chat id**, and which **Telegram account** the Bot API
|
|
63
|
+
* attributes the tap to (`callback_query.from.id`). It authenticates no
|
|
64
|
+
* person, because no transport can: an account id is evidence about an
|
|
65
|
+
* account.
|
|
66
|
+
*
|
|
67
|
+
* What is done with the second fact is the operator's to decide, and since
|
|
68
|
+
* APRV-324 there are two settings:
|
|
69
|
+
*
|
|
70
|
+
* - **No `senders` block in the policy.** Nothing changes from every build
|
|
71
|
+
* before it. The decision is recorded against the human actor the *runtime*
|
|
72
|
+
* was configured with (`APPROVAL_HUMAN` / `--as`), so the guarantee is
|
|
73
|
+
* "someone with access to the configured chat, on a runtime configured by
|
|
74
|
+
* someone with local control, tapped Approve" — not "alice tapped Approve".
|
|
75
|
+
* Anyone in that chat can approve as the configured actor. Use a private chat
|
|
76
|
+
* with the bot, and treat the chat's membership as part of the trust
|
|
77
|
+
* boundary.
|
|
78
|
+
* - **A `senders` block mapping account ids to approvers.** The decision is
|
|
79
|
+
* recorded against the person the operator attested that account to, and a
|
|
80
|
+
* tap from an account the policy does not name is REFUSED rather than
|
|
81
|
+
* recorded under the listener's identity. The guarantee becomes "the account
|
|
82
|
+
* the operator attested to alice tapped Approve", which is a statement about
|
|
83
|
+
* Telegram's session handling and the operator's assertion, and still not a
|
|
84
|
+
* proof of personhood. Cryptographic identity is future work and is not a
|
|
85
|
+
* v0.1 claim.
|
|
86
|
+
*
|
|
87
|
+
* The channel itself resolves nothing either way. It reports the account it
|
|
88
|
+
* saw; `channels/contract.ts` resolves it against the attested policy, and
|
|
89
|
+
* `core/gate.ts` decides. See `design/channel-sender-identity.md`.
|
|
53
90
|
*
|
|
54
91
|
* ## Formatting: HTML, not MarkdownV2 — a deliberate choice
|
|
55
92
|
*
|
|
@@ -183,6 +220,7 @@
|
|
|
183
220
|
* and the log is not opened.
|
|
184
221
|
*/
|
|
185
222
|
import type { ChannelBatch, ChannelDecision, ChannelHealth, ChannelRequest, DecisionOutcome, DeliveryId, RenderedRequest, TaggedField, TestableChannel } from "./contract.js";
|
|
223
|
+
import type { ChannelSender } from "../core/sender-identity.js";
|
|
186
224
|
import { type Reaction, type ReviewVerdict } from "../core/audit.js";
|
|
187
225
|
import { type PromptLayout } from "../core/prompt-layout.js";
|
|
188
226
|
export { TELEGRAM_CHAT_ENV, TELEGRAM_TOKEN_ENV, telegramChatEnvFor, telegramTokenEnvFor, } from "../core/telegram-config.js";
|
|
@@ -341,6 +379,13 @@ export declare function decidedLine(actor: string, ts: string, seq: number): str
|
|
|
341
379
|
export declare const TELEGRAM_DEFAULT_RETENTION_MS: number;
|
|
342
380
|
/** Least time between two sweeps. A sweep is O(map); once a minute is plenty. */
|
|
343
381
|
export declare const TELEGRAM_SWEEP_INTERVAL_MS = 60000;
|
|
382
|
+
/**
|
|
383
|
+
* How many refused cards' nonces a channel remembers as dead (APRV-442).
|
|
384
|
+
*
|
|
385
|
+
* A bound on memory and nothing else: a nonce that falls off the end reaches
|
|
386
|
+
* the action-reference fallback, and the gate judges that tap in full.
|
|
387
|
+
*/
|
|
388
|
+
export declare const TELEGRAM_REFUSED_NONCE_CAP = 1024;
|
|
344
389
|
/**
|
|
345
390
|
* The slice of `fetch` this module uses, structurally.
|
|
346
391
|
*
|
|
@@ -556,6 +601,13 @@ export type CheckpointTapHandler = (tap: {
|
|
|
556
601
|
seq: number;
|
|
557
602
|
hash: string;
|
|
558
603
|
};
|
|
604
|
+
/**
|
|
605
|
+
* The account the transport authenticated (APRV-324 follow-up), when it
|
|
606
|
+
* authenticated one. The channel resolves nothing: the runtime's handler
|
|
607
|
+
* asks the attested policy who this is, refuses an account it does not name,
|
|
608
|
+
* and signs as the person it does.
|
|
609
|
+
*/
|
|
610
|
+
sender?: ChannelSender;
|
|
559
611
|
}) => CheckpointTapResponse | Promise<CheckpointTapResponse>;
|
|
560
612
|
export declare const TELEGRAM_COMMANDS: readonly ["queue", "skip", "next"];
|
|
561
613
|
export type TelegramCommand = (typeof TELEGRAM_COMMANDS)[number];
|
|
@@ -804,6 +856,14 @@ export interface DigestState {
|
|
|
804
856
|
* the request's own `ts` remains the only instant a TTL is measured from.
|
|
805
857
|
*/
|
|
806
858
|
deliveredAtMs: number;
|
|
859
|
+
/**
|
|
860
|
+
* How long after {@link deliveredAtMs} the LAST of this digest's members can
|
|
861
|
+
* still be decided, or `null` when some member is bounded by nothing
|
|
862
|
+
* (APRV-423, second review pass). The widest of the members' own windows
|
|
863
|
+
* ({@link Delivery.windowMs}), because a digest is droppable only once every
|
|
864
|
+
* member is past deciding.
|
|
865
|
+
*/
|
|
866
|
+
windowMs: number | null;
|
|
807
867
|
}
|
|
808
868
|
/**
|
|
809
869
|
* The computed facts a digest's members share, as the digest states them.
|
|
@@ -904,6 +964,30 @@ export declare function parseCheckpointCallback(data: unknown): {
|
|
|
904
964
|
sign: boolean;
|
|
905
965
|
nonce: string;
|
|
906
966
|
} | null;
|
|
967
|
+
/**
|
|
968
|
+
* The account the Bot API attributes a callback to (APRV-324, amended SPEC.md
|
|
969
|
+
* §10.3).
|
|
970
|
+
*
|
|
971
|
+
* `callback_query.from.id` and nothing else. Telegram assembles the `from`
|
|
972
|
+
* object itself, from the session the tap arrived on, which is why it is the
|
|
973
|
+
* one field on an update this channel treats as evidence about a person. Three
|
|
974
|
+
* neighbours are deliberately not read:
|
|
975
|
+
*
|
|
976
|
+
* - **`from.username`.** Mutable and reusable, so a mapping keyed on it would
|
|
977
|
+
* hand an identity over with a handle. Never a key here and never recorded
|
|
978
|
+
* (`core/sender-identity.ts` states the argument in full).
|
|
979
|
+
* - **`message.from`.** The author of the message the button sits on — this bot
|
|
980
|
+
* — rather than the person who pressed it.
|
|
981
|
+
* - **`data`, and any text.** What the sender says about themselves, which
|
|
982
|
+
* §11.1 invariant 4 says may raise scrutiny and never lower it. A callback
|
|
983
|
+
* whose payload names a user id names it about itself; the id here comes from
|
|
984
|
+
* the transport, and the two disagreeing changes nothing.
|
|
985
|
+
*
|
|
986
|
+
* `undefined` when the update carries no usable id: a sender this channel could
|
|
987
|
+
* not read is not a sender it may guess at, and the decision then travels with
|
|
988
|
+
* none, which the contract reads as today's configured attribution.
|
|
989
|
+
*/
|
|
990
|
+
export declare function senderOf(query: Record<string, unknown>, channel: string): ChannelSender | undefined;
|
|
907
991
|
interface ParsedCallback {
|
|
908
992
|
decision: "grant" | "reject";
|
|
909
993
|
/** `all` for a digest's "all" button; `one` for every per-request button. */
|
|
@@ -978,6 +1062,18 @@ export interface ReviewTap {
|
|
|
978
1062
|
reaction?: Reaction;
|
|
979
1063
|
/** The human's words, when a note prompt collected any. */
|
|
980
1064
|
note?: string;
|
|
1065
|
+
/**
|
|
1066
|
+
* The account the transport authenticated (APRV-324 follow-up), when it
|
|
1067
|
+
* authenticated one.
|
|
1068
|
+
*
|
|
1069
|
+
* A review confers no authority, which is why it took the paragraph above so
|
|
1070
|
+
* long to stop being true. It is still recorded as a HUMAN's observation and
|
|
1071
|
+
* `approval feedback` presents it to agents as human-authored guidance, so a
|
|
1072
|
+
* review attributed to the wrong person is guidance in somebody else's name.
|
|
1073
|
+
* The channel resolves nothing; the runtime's handler asks the attested
|
|
1074
|
+
* policy, refuses an account it does not name, and records the one it does.
|
|
1075
|
+
*/
|
|
1076
|
+
sender?: ChannelSender;
|
|
981
1077
|
}
|
|
982
1078
|
/** What the runtime did with a review tap, as it reports it back. */
|
|
983
1079
|
export interface ReviewTapResponse {
|
|
@@ -1051,11 +1147,20 @@ export interface ReviewCardState {
|
|
|
1051
1147
|
headline: string;
|
|
1052
1148
|
lines: string[];
|
|
1053
1149
|
} | null;
|
|
1054
|
-
/**
|
|
1150
|
+
/**
|
|
1151
|
+
* The outstanding note prompt, and what its reply will record.
|
|
1152
|
+
*
|
|
1153
|
+
* `sender` is the account that asked for the prompt (APRV-324 follow-up),
|
|
1154
|
+
* when the transport authenticated one. A ForceReply prompt is addressed to
|
|
1155
|
+
* the person who tapped, and the words it collects are recorded as theirs, so
|
|
1156
|
+
* a reply from a different account is not the answer to this question: it is
|
|
1157
|
+
* left unrecorded and the prompt stays live for whoever armed it.
|
|
1158
|
+
*/
|
|
1055
1159
|
awaitingNote: {
|
|
1056
1160
|
promptId: DeliveryId;
|
|
1057
1161
|
verdict: ReviewVerdict;
|
|
1058
1162
|
reaction: Reaction;
|
|
1163
|
+
sender?: ChannelSender;
|
|
1059
1164
|
} | null;
|
|
1060
1165
|
/** When this process delivered the card, on {@link TelegramConfig.now}'s clock. */
|
|
1061
1166
|
deliveredAtMs: number;
|
|
@@ -1161,6 +1266,17 @@ export declare class TelegramApiError extends Error {
|
|
|
1161
1266
|
* that goes unreported.
|
|
1162
1267
|
*/
|
|
1163
1268
|
export declare function isMessageNotModified(cause: unknown): boolean;
|
|
1269
|
+
/**
|
|
1270
|
+
* Whether a failed poll is the Bot API saying another process holds this bot
|
|
1271
|
+
* (APRV-390).
|
|
1272
|
+
*
|
|
1273
|
+
* It is the one poll failure that is not transient and not the network's
|
|
1274
|
+
* fault: retrying it forever produces an identical line every few seconds and
|
|
1275
|
+
* never recovers, because the other poller is not going to stop. {@link
|
|
1276
|
+
* TelegramChannel.listen} reports it once, with whatever the caller knows
|
|
1277
|
+
* about who the other process is, and then stops repeating itself.
|
|
1278
|
+
*/
|
|
1279
|
+
export declare function isPollConflict(cause: unknown): boolean;
|
|
1164
1280
|
/** What one `pollOnce()` did, for tests and for programmatic drivers. */
|
|
1165
1281
|
export interface TelegramPollResult {
|
|
1166
1282
|
/** Updates received in this batch. */
|
|
@@ -1187,6 +1303,50 @@ export interface TelegramPollResult {
|
|
|
1187
1303
|
ok: boolean;
|
|
1188
1304
|
}[];
|
|
1189
1305
|
}
|
|
1306
|
+
/**
|
|
1307
|
+
* How updates reach this channel (APRV-424).
|
|
1308
|
+
*
|
|
1309
|
+
* `poll` is `getUpdates`, the transport every build before APRV-424 had.
|
|
1310
|
+
* `webhook` is Telegram posting each update to a URL the runtime registered.
|
|
1311
|
+
* They are alternatives and never a pair: the Bot API refuses `getUpdates`
|
|
1312
|
+
* outright while a webhook is set, so a process that did both would spend its
|
|
1313
|
+
* life in a 409 loop and the approver's tap would land on whichever half was
|
|
1314
|
+
* lucky.
|
|
1315
|
+
*/
|
|
1316
|
+
export type TelegramTransport = "poll" | "webhook";
|
|
1317
|
+
/**
|
|
1318
|
+
* Why a transport claim was refused. Frozen, per SPEC §11.1 invariant 6.
|
|
1319
|
+
*
|
|
1320
|
+
* One code, because there is one fact: this channel is already receiving
|
|
1321
|
+
* updates by the other transport.
|
|
1322
|
+
*/
|
|
1323
|
+
export declare const TELEGRAM_TRANSPORT_REFUSAL_CODES: readonly ["transport-conflict"];
|
|
1324
|
+
export type TelegramTransportRefusalCode = (typeof TELEGRAM_TRANSPORT_REFUSAL_CODES)[number];
|
|
1325
|
+
export type TelegramTransportClaim = {
|
|
1326
|
+
ok: true;
|
|
1327
|
+
transport: TelegramTransport;
|
|
1328
|
+
} | {
|
|
1329
|
+
ok: false;
|
|
1330
|
+
code: TelegramTransportRefusalCode;
|
|
1331
|
+
message: string;
|
|
1332
|
+
};
|
|
1333
|
+
/**
|
|
1334
|
+
* The in-process half of "long-poll and webhook are mutually exclusive"
|
|
1335
|
+
* (APRV-424).
|
|
1336
|
+
*
|
|
1337
|
+
* It is a belt on the braces and says so. The exclusion that matters is per
|
|
1338
|
+
* BOT and lives above this class, where a process can ask the Bot API
|
|
1339
|
+
* (`getWebhookInfo`) and the per-machine ownership registry who else is
|
|
1340
|
+
* receiving this bot's updates; a channel object knows only about itself.
|
|
1341
|
+
* What this rules out is the one failure a caller could cause here and
|
|
1342
|
+
* nowhere else: feeding one channel instance from both a poll loop and an
|
|
1343
|
+
* HTTP handler, where `handleUpdate`'s single ack slot and the delivery maps
|
|
1344
|
+
* would be written by two arrivals nobody ordered.
|
|
1345
|
+
*/
|
|
1346
|
+
export declare class TelegramTransportError extends Error {
|
|
1347
|
+
readonly code: TelegramTransportRefusalCode;
|
|
1348
|
+
constructor(message: string);
|
|
1349
|
+
}
|
|
1190
1350
|
export interface TelegramListenOptions {
|
|
1191
1351
|
/** Process exactly one successful `getUpdates` batch, then return. */
|
|
1192
1352
|
once?: boolean;
|
|
@@ -1206,6 +1366,17 @@ export interface TelegramListenOptions {
|
|
|
1206
1366
|
* failure mode this loop exists to rule out.
|
|
1207
1367
|
*/
|
|
1208
1368
|
beforePoll?: () => Promise<void>;
|
|
1369
|
+
/**
|
|
1370
|
+
* What the caller knows about who else might be polling this bot (APRV-390).
|
|
1371
|
+
*
|
|
1372
|
+
* Consulted only when a poll fails with the Bot API's 409, and appended to
|
|
1373
|
+
* the one line that failure produces. The CLI builds it from the per-machine
|
|
1374
|
+
* ownership registry (`core/channel-owner.ts`), so this class keeps no
|
|
1375
|
+
* knowledge of instances, directories or files — it asks the question and
|
|
1376
|
+
* prints the caller's answer, the same arrangement {@link
|
|
1377
|
+
* TelegramConfig.describeAction} uses for the log.
|
|
1378
|
+
*/
|
|
1379
|
+
conflictAdvice?: () => string | null;
|
|
1209
1380
|
}
|
|
1210
1381
|
/**
|
|
1211
1382
|
* What {@link TelegramChannel.notifyBatch} did with a set (APRV-115).
|
|
@@ -1299,11 +1470,60 @@ export declare class TelegramChannel implements TestableChannel {
|
|
|
1299
1470
|
private readonly digests;
|
|
1300
1471
|
/** "All" nonce -> the digest message it was issued for. */
|
|
1301
1472
|
private readonly allNonces;
|
|
1473
|
+
/**
|
|
1474
|
+
* Action keys whose card this process disarmed on a tap the gate did NOT
|
|
1475
|
+
* settle (APRV-442): a refusal (`sender-unmapped`, a budget, an unattested
|
|
1476
|
+
* policy, anything `ok: false`) or a handler that threw. Drained by
|
|
1477
|
+
* {@link takeReleased}.
|
|
1478
|
+
*
|
|
1479
|
+
* The disarm is right and stays, and {@link refusedNonces} keeps it final:
|
|
1480
|
+
* the refused card's bytes resolve to nothing, not even through the
|
|
1481
|
+
* action-reference fallback to the card that replaces it. What the disarm
|
|
1482
|
+
* must not do is leave the listener believing the REQUEST is on the
|
|
1483
|
+
* approver's phone, which is what `DispatchState.delivered` goes on saying
|
|
1484
|
+
* until something tells it otherwise. This set is that something: it names
|
|
1485
|
+
* a card, never an outcome, and the listener re-derives from the verified
|
|
1486
|
+
* log whether the request is still pending before it offers a new card.
|
|
1487
|
+
* Nothing here decides, and losing it to a restart costs nothing, because a
|
|
1488
|
+
* restarted listener re-sends everything pending anyway.
|
|
1489
|
+
*/
|
|
1490
|
+
private readonly released;
|
|
1491
|
+
/**
|
|
1492
|
+
* Nonces of cards a refused or failed tap disarmed (APRV-442), oldest first,
|
|
1493
|
+
* capped at {@link TELEGRAM_REFUSED_NONCE_CAP}.
|
|
1494
|
+
*
|
|
1495
|
+
* Without this, a released request's fresh card would give the refused
|
|
1496
|
+
* card's bytes somewhere to go: the nonce misses, the action reference
|
|
1497
|
+
* resolves to the new live card, and a Telegram redelivery of the refused
|
|
1498
|
+
* tap (a webhook retry) or a client replaying the removed buttons would be
|
|
1499
|
+
* refused again, append again, disarm the new card and cause another
|
|
1500
|
+
* re-send, once per replay. A nonce in this set never takes the fallback, so
|
|
1501
|
+
* a refused card stays exactly as dead as it was before APRV-442 and only
|
|
1502
|
+
* the REQUEST is offered again. Forgetting an entry past the cap degrades to
|
|
1503
|
+
* the fallback, whose tap the gate still judges in full: volume, never a
|
|
1504
|
+
* decision.
|
|
1505
|
+
*/
|
|
1506
|
+
private readonly refusedNonces;
|
|
1302
1507
|
private rendered;
|
|
1303
1508
|
private offset;
|
|
1304
1509
|
private counter;
|
|
1305
1510
|
private stopped;
|
|
1306
1511
|
private inFlight;
|
|
1512
|
+
/**
|
|
1513
|
+
* The transport this channel has started receiving updates by, or `null`
|
|
1514
|
+
* before the first one (APRV-424). Sticky for the life of the object: a
|
|
1515
|
+
* process that stopped polling has not stopped being a poller, and the
|
|
1516
|
+
* question this answers is which arrival path owns the maps below.
|
|
1517
|
+
*/
|
|
1518
|
+
private transport;
|
|
1519
|
+
/**
|
|
1520
|
+
* Everything {@link redact} scrubs out of anything that leaves this class.
|
|
1521
|
+
*
|
|
1522
|
+
* The bot token from construction, plus any secret a later call was handed:
|
|
1523
|
+
* {@link registerWebhook} adds the `secret_token` before it sends it, so a
|
|
1524
|
+
* Bot API error quoting the request cannot put it on an operator's terminal.
|
|
1525
|
+
*/
|
|
1526
|
+
private readonly secrets;
|
|
1307
1527
|
private readonly counters;
|
|
1308
1528
|
constructor(config: TelegramConfig);
|
|
1309
1529
|
onDecision(handler: (decision: ChannelDecision) => DecisionOutcome): void;
|
|
@@ -1459,6 +1679,28 @@ export declare class TelegramChannel implements TestableChannel {
|
|
|
1459
1679
|
* a decided one is not that.
|
|
1460
1680
|
*/
|
|
1461
1681
|
private disarm;
|
|
1682
|
+
/**
|
|
1683
|
+
* How long after delivery the request behind a prompt can still be decided,
|
|
1684
|
+
* on this process's clock, or `null` when nothing bounds it (APRV-423, second
|
|
1685
|
+
* review pass).
|
|
1686
|
+
*
|
|
1687
|
+
* The SHORTER of two bounds, each of which is at or past the gate's own
|
|
1688
|
+
* lapse, so the sweep never forgets a button a decision could still reach:
|
|
1689
|
+
*
|
|
1690
|
+
* - the request's `ttl_remaining_ms`, computed by the listener from the
|
|
1691
|
+
* verified log against the window the gate judges by (the policy's TTL
|
|
1692
|
+
* narrowed by the harness cap the requesting hook declared). It was
|
|
1693
|
+
* measured at tagging time, and delivery is at or after tagging, so
|
|
1694
|
+
* counting it from delivery ends at or after the real lapse;
|
|
1695
|
+
* - the policy's own TTL ({@link TelegramConfig.approvalTtlMs}), counted from
|
|
1696
|
+
* delivery, which is at or after the `approval.requested` it really runs
|
|
1697
|
+
* from. This was the only bound before APRV-423 and it stays as one.
|
|
1698
|
+
*
|
|
1699
|
+
* A request neither bounds is decidable forever, and its entry is dropped
|
|
1700
|
+
* only on an observed settlement. This channel still reads no policy and no
|
|
1701
|
+
* log: both numbers arrive computed, by the verb and by the tagger.
|
|
1702
|
+
*/
|
|
1703
|
+
private retentionWindowMs;
|
|
1462
1704
|
/**
|
|
1463
1705
|
* Drop the delivery bookkeeping no callback can still be honoured against
|
|
1464
1706
|
* (APRV-135).
|
|
@@ -1552,6 +1794,28 @@ export declare class TelegramChannel implements TestableChannel {
|
|
|
1552
1794
|
* {@link Channel} interface names. Its wording is unchanged.
|
|
1553
1795
|
*/
|
|
1554
1796
|
retract(deliveryId: DeliveryId, reason: string, actionKey?: string): Promise<void>;
|
|
1797
|
+
/**
|
|
1798
|
+
* The action keys whose card a refused or failed tap disarmed since the last
|
|
1799
|
+
* call, and forget them (APRV-442).
|
|
1800
|
+
*
|
|
1801
|
+
* The listener's dispatch cycle calls this once per cycle and offers a fresh
|
|
1802
|
+
* card for every key the verified log still calls pending. It is a statement
|
|
1803
|
+
* about this process's cards and nothing else: it carries no decision, no
|
|
1804
|
+
* sender and no outcome, and a key in it that the log has since settled is
|
|
1805
|
+
* simply not offered.
|
|
1806
|
+
*/
|
|
1807
|
+
takeReleased(): string[];
|
|
1808
|
+
/**
|
|
1809
|
+
* Mark `delivery`'s card dead and its request released, BEFORE the
|
|
1810
|
+
* annotation that disarms it (APRV-442).
|
|
1811
|
+
*
|
|
1812
|
+
* Every nonce still armed for this request on this message is recorded in
|
|
1813
|
+
* {@link refusedNonces}, together with the nonce the tap carried (which
|
|
1814
|
+
* differs when the tap came from an earlier copy through the fallback), so
|
|
1815
|
+
* none of those bytes can later resolve to the fresh card. On a digest only
|
|
1816
|
+
* this member's nonce is taken: its siblings stay armed on the digest.
|
|
1817
|
+
*/
|
|
1818
|
+
private release;
|
|
1555
1819
|
/**
|
|
1556
1820
|
* Send one plain message that carries no question (APRV-196).
|
|
1557
1821
|
*
|
|
@@ -1563,6 +1827,24 @@ export declare class TelegramChannel implements TestableChannel {
|
|
|
1563
1827
|
* HTML-mode message is.
|
|
1564
1828
|
*/
|
|
1565
1829
|
announce(lines: string[]): Promise<DeliveryId>;
|
|
1830
|
+
/**
|
|
1831
|
+
* Which bot this token is, from one `getMe` (APRV-390).
|
|
1832
|
+
*
|
|
1833
|
+
* `getMe` is the only Bot API call that answers it, and it is the call
|
|
1834
|
+
* `approval doctor` and `approval setup channel telegram` already make for
|
|
1835
|
+
* the same reason: it mutates nothing, sends nothing, and acknowledges
|
|
1836
|
+
* nothing. In particular it is NOT `getUpdates`, so asking who this bot is
|
|
1837
|
+
* consumes no update and steals no pending tap from a listener that is
|
|
1838
|
+
* already running — which matters here above all, because the answer is
|
|
1839
|
+
* what decides whether this process is allowed to poll at all.
|
|
1840
|
+
*
|
|
1841
|
+
* Throws {@link TelegramApiError} like every other call; the caller decides
|
|
1842
|
+
* whether an unreachable Bot API is a refusal or a shrug.
|
|
1843
|
+
*/
|
|
1844
|
+
identify(): Promise<{
|
|
1845
|
+
id: string;
|
|
1846
|
+
username: string;
|
|
1847
|
+
}>;
|
|
1566
1848
|
/**
|
|
1567
1849
|
* Long-poll `getUpdates` until {@link stop} is called (or one batch, with
|
|
1568
1850
|
* `once`).
|
|
@@ -1588,6 +1870,99 @@ export declare class TelegramChannel implements TestableChannel {
|
|
|
1588
1870
|
* what {@link listen} catches and retries.
|
|
1589
1871
|
*/
|
|
1590
1872
|
pollOnce(): Promise<TelegramPollResult>;
|
|
1873
|
+
/**
|
|
1874
|
+
* Which update types this channel asks for, on either transport (APRV-424).
|
|
1875
|
+
*
|
|
1876
|
+
* APRV-216. `message` is asked for only while a command handler is
|
|
1877
|
+
* registered: see {@link onCommand} for why a listener that reads messages
|
|
1878
|
+
* nobody asked for would break `approval setup channel telegram`'s chat
|
|
1879
|
+
* discovery. APRV-299 adds the second reason to read messages: a `loved` or
|
|
1880
|
+
* `disliked` on a review card collects the human's words as a REPLY, because
|
|
1881
|
+
* an inline keyboard has no text input.
|
|
1882
|
+
*
|
|
1883
|
+
* One function since APRV-424, because `setWebhook` takes the same list as
|
|
1884
|
+
* `getUpdates` and two spellings of it would be two answers to "what does
|
|
1885
|
+
* this listener read" — with the webhook's answer frozen at registration
|
|
1886
|
+
* time, where nobody would look for it.
|
|
1887
|
+
*/
|
|
1888
|
+
allowedUpdates(): string[];
|
|
1889
|
+
/**
|
|
1890
|
+
* One update, from whichever transport carried it (APRV-424).
|
|
1891
|
+
*
|
|
1892
|
+
* The whole of what the webhook adds is the ARRIVAL. Everything a tap then
|
|
1893
|
+
* passes through — the chat check, `senderOf`, the checkpoint and review
|
|
1894
|
+
* parsers, the resolution ladder, the early ack, `this.handler` and the
|
|
1895
|
+
* annotation written from the record the gate appended — is
|
|
1896
|
+
* {@link handleUpdate}, called from here and from {@link pollOnce}, and
|
|
1897
|
+
* there is no second copy of any of it. `tests/telegram-webhook.test.ts`
|
|
1898
|
+
* drives one callback through both entry points and compares the records the
|
|
1899
|
+
* log ends up holding.
|
|
1900
|
+
*
|
|
1901
|
+
* The sweep is `pollOnce`'s, for `pollOnce`'s reason: this is the moment the
|
|
1902
|
+
* process is about to be idle, and a channel that only ever wakes for taps
|
|
1903
|
+
* would otherwise never run one.
|
|
1904
|
+
*/
|
|
1905
|
+
deliverUpdate(update: unknown): Promise<TelegramPollResult>;
|
|
1906
|
+
/** The per-update bookkeeping both transports do, before `handleUpdate`. */
|
|
1907
|
+
private intake;
|
|
1908
|
+
/**
|
|
1909
|
+
* Bind this channel to one transport, or say which one already holds it
|
|
1910
|
+
* (APRV-424).
|
|
1911
|
+
*
|
|
1912
|
+
* Idempotent for the transport already claimed, so a webhook server that
|
|
1913
|
+
* claims at start-up and then delivers, or a driver calling `pollOnce` in a
|
|
1914
|
+
* loop, pays nothing. Not released by {@link stop}: a process that stopped
|
|
1915
|
+
* polling has not stopped being a poller, and re-pointing a live channel's
|
|
1916
|
+
* delivery maps at a second arrival path is the state this exists to refuse.
|
|
1917
|
+
*/
|
|
1918
|
+
claimTransport(transport: TelegramTransport): TelegramTransportClaim;
|
|
1919
|
+
/** {@link claimTransport}, for the paths where a refusal is a caller's bug. */
|
|
1920
|
+
private claimOrThrow;
|
|
1921
|
+
/**
|
|
1922
|
+
* Point this bot's updates at `url`, and require `secret` on every post.
|
|
1923
|
+
*
|
|
1924
|
+
* Three properties, and each is a refusal to be clever:
|
|
1925
|
+
*
|
|
1926
|
+
* - **The secret is Telegram's own mechanism**, `secret_token`, echoed back
|
|
1927
|
+
* on every delivery in the `X-Telegram-Bot-Api-Secret-Token` header. The
|
|
1928
|
+
* receiver compares it and refuses anything else, so a URL that leaks (a
|
|
1929
|
+
* proxy log, a referrer, a screenshot) is a URL that still decides
|
|
1930
|
+
* nothing.
|
|
1931
|
+
* - **It is redacted from this moment on.** The value is added to the
|
|
1932
|
+
* channel's secret list BEFORE the call, so a Bot API error that quotes
|
|
1933
|
+
* the request cannot print it.
|
|
1934
|
+
* - **Pending updates are kept.** `drop_pending_updates` is left false:
|
|
1935
|
+
* taps that arrived while the process was down are the approver's answers,
|
|
1936
|
+
* and the gate is what decides whether they are still honourable.
|
|
1937
|
+
*/
|
|
1938
|
+
registerWebhook(url: string, secret: string): Promise<void>;
|
|
1939
|
+
/**
|
|
1940
|
+
* Take this bot's webhook away, so `getUpdates` works again.
|
|
1941
|
+
*
|
|
1942
|
+
* Called on a clean stop of the webhook runner. Pending updates are kept for
|
|
1943
|
+
* {@link registerWebhook}'s reason: the next process to start — a poller or
|
|
1944
|
+
* another webhook — is entitled to the taps that arrived in between.
|
|
1945
|
+
*
|
|
1946
|
+
* `timeoutMs` is what the stop path passes, and it is shorter than this
|
|
1947
|
+
* channel's ordinary request timeout on purpose (APRV-424, second review,
|
|
1948
|
+
* note 6). A stop already waits for the receiver to drain, and an operator
|
|
1949
|
+
* pressing Ctrl-C a second time is asking for the process to end: half a
|
|
1950
|
+
* minute of an unreachable Bot API on top of that reads as a hang, and the
|
|
1951
|
+
* webhook it failed to remove is reported rather than silently retried.
|
|
1952
|
+
*/
|
|
1953
|
+
deleteWebhook(timeoutMs?: number): Promise<void>;
|
|
1954
|
+
/**
|
|
1955
|
+
* What the Bot API says is receiving this bot's updates right now.
|
|
1956
|
+
*
|
|
1957
|
+
* The one authority on the question, and the reason it is asked at start-up
|
|
1958
|
+
* by both transports: the ownership registry knows about processes on THIS
|
|
1959
|
+
* machine, and a webhook registered from a laptop in another timezone is
|
|
1960
|
+
* still a webhook swallowing every tap this poller is waiting for.
|
|
1961
|
+
*/
|
|
1962
|
+
webhookInfo(): Promise<{
|
|
1963
|
+
url: string;
|
|
1964
|
+
pendingUpdateCount: number;
|
|
1965
|
+
}>;
|
|
1591
1966
|
/**
|
|
1592
1967
|
* Exactly one `answerCallbackQuery` per callback query, on every path
|
|
1593
1968
|
* (APRV-196).
|
|
@@ -1807,7 +2182,14 @@ export declare class TelegramChannel implements TestableChannel {
|
|
|
1807
2182
|
* settled, so a member still in the map is one still armed on a live message.
|
|
1808
2183
|
*/
|
|
1809
2184
|
private liveDeliveryFor;
|
|
1810
|
-
/**
|
|
2185
|
+
/**
|
|
2186
|
+
* Replace every secret this channel holds with a placeholder in `text`.
|
|
2187
|
+
*
|
|
2188
|
+
* The bot token always, and since APRV-424 the webhook `secret_token` too,
|
|
2189
|
+
* from the moment {@link registerWebhook} is handed it. Both are values that
|
|
2190
|
+
* only ever travel TO the Bot API, so anything coming back that quotes one
|
|
2191
|
+
* is a diagnostic about to print a credential.
|
|
2192
|
+
*/
|
|
1811
2193
|
private redact;
|
|
1812
2194
|
private describe;
|
|
1813
2195
|
/**
|