@cello-protocol/daemon 0.0.227 → 0.0.229
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/dist/agent-admin-handlers.d.ts +56 -0
- package/dist/agent-admin-handlers.d.ts.map +1 -0
- package/dist/agent-admin-handlers.js +73 -0
- package/dist/agent-admin-handlers.js.map +1 -0
- package/dist/agent-handlers.d.ts +72 -0
- package/dist/agent-handlers.d.ts.map +1 -0
- package/dist/agent-handlers.js +604 -0
- package/dist/agent-handlers.js.map +1 -0
- package/dist/agent-id-migration.d.ts +70 -0
- package/dist/agent-id-migration.d.ts.map +1 -0
- package/dist/agent-id-migration.js +468 -0
- package/dist/agent-id-migration.js.map +1 -0
- package/dist/agent-loader.d.ts +37 -0
- package/dist/agent-loader.d.ts.map +1 -0
- package/dist/agent-loader.js +37 -0
- package/dist/agent-loader.js.map +1 -0
- package/dist/agent-selection-root.d.ts +29 -0
- package/dist/agent-selection-root.d.ts.map +1 -0
- package/dist/agent-selection-root.js +126 -0
- package/dist/agent-selection-root.js.map +1 -0
- package/dist/agent-selection.d.ts +73 -0
- package/dist/agent-selection.d.ts.map +1 -0
- package/dist/agent-selection.js +80 -0
- package/dist/agent-selection.js.map +1 -0
- package/dist/agent-settings-keys.d.ts +52 -0
- package/dist/agent-settings-keys.d.ts.map +1 -0
- package/dist/agent-settings-keys.js +114 -0
- package/dist/agent-settings-keys.js.map +1 -0
- package/dist/agent-state.d.ts +67 -0
- package/dist/agent-state.d.ts.map +1 -0
- package/dist/agent-state.js +66 -0
- package/dist/agent-state.js.map +1 -0
- package/dist/assignment-verify.d.ts +90 -0
- package/dist/assignment-verify.d.ts.map +1 -0
- package/dist/assignment-verify.js +301 -0
- package/dist/assignment-verify.js.map +1 -0
- package/dist/attendance-wiring.d.ts +23 -0
- package/dist/attendance-wiring.d.ts.map +1 -0
- package/dist/attendance-wiring.js +248 -0
- package/dist/attendance-wiring.js.map +1 -0
- package/dist/attestation-body.d.ts +47 -0
- package/dist/attestation-body.d.ts.map +1 -0
- package/dist/attestation-body.js +71 -0
- package/dist/attestation-body.js.map +1 -0
- package/dist/authorship-verification.d.ts +91 -0
- package/dist/authorship-verification.d.ts.map +1 -0
- package/dist/authorship-verification.js +532 -0
- package/dist/authorship-verification.js.map +1 -0
- package/dist/away-detection.d.ts +139 -0
- package/dist/away-detection.d.ts.map +1 -0
- package/dist/away-detection.js +186 -0
- package/dist/away-detection.js.map +1 -0
- package/dist/away-inbox-oneshot.d.ts +40 -0
- package/dist/away-inbox-oneshot.d.ts.map +1 -0
- package/dist/away-inbox-oneshot.js +311 -0
- package/dist/away-inbox-oneshot.js.map +1 -0
- package/dist/backup-restore-handlers.d.ts +10 -0
- package/dist/backup-restore-handlers.d.ts.map +1 -0
- package/dist/backup-restore-handlers.js +82 -0
- package/dist/backup-restore-handlers.js.map +1 -0
- package/dist/backup-restore.d.ts +102 -0
- package/dist/backup-restore.d.ts.map +1 -0
- package/dist/backup-restore.js +341 -0
- package/dist/backup-restore.js.map +1 -0
- package/dist/bin/cello-daemon.d.ts +13 -0
- package/dist/bin/cello-daemon.d.ts.map +1 -0
- package/dist/bin/cello-daemon.js.map +1 -0
- package/dist/boot-agents.d.ts +64 -0
- package/dist/boot-agents.d.ts.map +1 -0
- package/dist/boot-agents.js +241 -0
- package/dist/boot-agents.js.map +1 -0
- package/dist/boot-connection-state.d.ts +38 -0
- package/dist/boot-connection-state.d.ts.map +1 -0
- package/dist/boot-connection-state.js +95 -0
- package/dist/boot-connection-state.js.map +1 -0
- package/dist/boot-core.d.ts +36 -0
- package/dist/boot-core.d.ts.map +1 -0
- package/dist/boot-core.js +293 -0
- package/dist/boot-core.js.map +1 -0
- package/dist/boot-parked-content.d.ts +34 -0
- package/dist/boot-parked-content.d.ts.map +1 -0
- package/dist/boot-parked-content.js +528 -0
- package/dist/boot-parked-content.js.map +1 -0
- package/dist/boot-sweeps.d.ts +22 -0
- package/dist/boot-sweeps.d.ts.map +1 -0
- package/dist/boot-sweeps.js +51 -0
- package/dist/boot-sweeps.js.map +1 -0
- package/dist/bundled-consortium-manifest.d.ts +47 -0
- package/dist/bundled-consortium-manifest.d.ts.map +1 -0
- package/dist/bundled-consortium-manifest.js +116 -0
- package/dist/bundled-consortium-manifest.js.map +1 -0
- package/dist/cbor-blob-migration.d.ts +8 -0
- package/dist/cbor-blob-migration.d.ts.map +1 -0
- package/dist/cbor-blob-migration.js +116 -0
- package/dist/cbor-blob-migration.js.map +1 -0
- package/dist/challenge-verifier.d.ts +12 -0
- package/dist/challenge-verifier.d.ts.map +1 -0
- package/dist/challenge-verifier.js +11 -0
- package/dist/challenge-verifier.js.map +1 -0
- package/dist/channel-log-store.d.ts +80 -0
- package/dist/channel-log-store.d.ts.map +1 -0
- package/dist/channel-log-store.js +290 -0
- package/dist/channel-log-store.js.map +1 -0
- package/dist/close-commitment.d.ts +67 -0
- package/dist/close-commitment.d.ts.map +1 -0
- package/dist/close-commitment.js +78 -0
- package/dist/close-commitment.js.map +1 -0
- package/dist/close-session-handler.d.ts +94 -0
- package/dist/close-session-handler.d.ts.map +1 -0
- package/dist/close-session-handler.js +1418 -0
- package/dist/close-session-handler.js.map +1 -0
- package/dist/co-attendance.d.ts +29 -0
- package/dist/co-attendance.d.ts.map +1 -0
- package/dist/co-attendance.js +32 -0
- package/dist/co-attendance.js.map +1 -0
- package/dist/column-birth.d.ts +40 -0
- package/dist/column-birth.d.ts.map +1 -0
- package/dist/column-birth.js +61 -0
- package/dist/column-birth.js.map +1 -0
- package/dist/connect-or-start.d.ts +25 -0
- package/dist/connect-or-start.d.ts.map +1 -0
- package/dist/connect-or-start.js +175 -0
- package/dist/connect-or-start.js.map +1 -0
- package/dist/connection-agents.d.ts +16 -0
- package/dist/connection-agents.d.ts.map +1 -0
- package/dist/connection-agents.js +68 -0
- package/dist/connection-agents.js.map +1 -0
- package/dist/consent-migration.d.ts +49 -0
- package/dist/consent-migration.d.ts.map +1 -0
- package/dist/consent-migration.js +128 -0
- package/dist/consent-migration.js.map +1 -0
- package/dist/consortium-bootstrap.d.ts +138 -0
- package/dist/consortium-bootstrap.d.ts.map +1 -0
- package/dist/consortium-bootstrap.js +339 -0
- package/dist/consortium-bootstrap.js.map +1 -0
- package/dist/consortium-fingerprint.d.ts +115 -0
- package/dist/consortium-fingerprint.d.ts.map +1 -0
- package/dist/consortium-fingerprint.js +175 -0
- package/dist/consortium-fingerprint.js.map +1 -0
- package/dist/contact-handlers.d.ts +59 -0
- package/dist/contact-handlers.d.ts.map +1 -0
- package/dist/contact-handlers.js +343 -0
- package/dist/contact-handlers.js.map +1 -0
- package/dist/contact-pubkey-case.d.ts +65 -0
- package/dist/contact-pubkey-case.d.ts.map +1 -0
- package/dist/contact-pubkey-case.js +136 -0
- package/dist/contact-pubkey-case.js.map +1 -0
- package/dist/contacts-tier-migration.d.ts +90 -0
- package/dist/contacts-tier-migration.d.ts.map +1 -0
- package/dist/contacts-tier-migration.js +150 -0
- package/dist/contacts-tier-migration.js.map +1 -0
- package/dist/content-encryption-status.d.ts +111 -0
- package/dist/content-encryption-status.d.ts.map +1 -0
- package/dist/content-encryption-status.js +158 -0
- package/dist/content-encryption-status.js.map +1 -0
- package/dist/content-park-client.d.ts +90 -0
- package/dist/content-park-client.d.ts.map +1 -0
- package/dist/content-park-client.js +362 -0
- package/dist/content-park-client.js.map +1 -0
- package/dist/content-park.d.ts +52 -0
- package/dist/content-park.d.ts.map +1 -0
- package/dist/content-park.js +1309 -0
- package/dist/content-park.js.map +1 -0
- package/dist/cross-node-negotiation.d.ts +44 -0
- package/dist/cross-node-negotiation.d.ts.map +1 -0
- package/dist/cross-node-negotiation.js +34 -0
- package/dist/cross-node-negotiation.js.map +1 -0
- package/dist/daemon-handle.d.ts +57 -0
- package/dist/daemon-handle.d.ts.map +1 -0
- package/dist/daemon-handle.js +2 -0
- package/dist/daemon-handle.js.map +1 -0
- package/dist/daemon-status-report.d.ts +50 -0
- package/dist/daemon-status-report.d.ts.map +1 -0
- package/dist/daemon-status-report.js +81 -0
- package/dist/daemon-status-report.js.map +1 -0
- package/dist/daemon.d.ts +45 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +1177 -0
- package/dist/daemon.js.map +1 -0
- package/dist/db-identity-store.d.ts +159 -0
- package/dist/db-identity-store.d.ts.map +1 -0
- package/dist/db-identity-store.js +502 -0
- package/dist/db-identity-store.js.map +1 -0
- package/dist/delivery-open-registry.d.ts +92 -0
- package/dist/delivery-open-registry.d.ts.map +1 -0
- package/dist/delivery-open-registry.js +121 -0
- package/dist/delivery-open-registry.js.map +1 -0
- package/dist/delivery-session-suspects.d.ts +56 -0
- package/dist/delivery-session-suspects.d.ts.map +1 -0
- package/dist/delivery-session-suspects.js +94 -0
- package/dist/delivery-session-suspects.js.map +1 -0
- package/dist/directory-auth-posture.d.ts +87 -0
- package/dist/directory-auth-posture.d.ts.map +1 -0
- package/dist/directory-auth-posture.js +134 -0
- package/dist/directory-auth-posture.js.map +1 -0
- package/dist/directory-bootstrap.d.ts +310 -0
- package/dist/directory-bootstrap.d.ts.map +1 -0
- package/dist/directory-bootstrap.js +557 -0
- package/dist/directory-bootstrap.js.map +1 -0
- package/dist/directory-connect.d.ts +27 -0
- package/dist/directory-connect.d.ts.map +1 -0
- package/dist/directory-connect.js +106 -0
- package/dist/directory-connect.js.map +1 -0
- package/dist/disconnect-cleanup.d.ts +51 -0
- package/dist/disconnect-cleanup.d.ts.map +1 -0
- package/dist/disconnect-cleanup.js +72 -0
- package/dist/disconnect-cleanup.js.map +1 -0
- package/dist/document-amendment-store.d.ts +120 -0
- package/dist/document-amendment-store.d.ts.map +1 -0
- package/dist/document-amendment-store.js +266 -0
- package/dist/document-amendment-store.js.map +1 -0
- package/dist/document-delivery-transport.d.ts +168 -0
- package/dist/document-delivery-transport.d.ts.map +1 -0
- package/dist/document-delivery-transport.js +206 -0
- package/dist/document-delivery-transport.js.map +1 -0
- package/dist/document-engine.d.ts +134 -0
- package/dist/document-engine.d.ts.map +1 -0
- package/dist/document-engine.js +282 -0
- package/dist/document-engine.js.map +1 -0
- package/dist/document-flag.d.ts +58 -0
- package/dist/document-flag.d.ts.map +1 -0
- package/dist/document-flag.js +70 -0
- package/dist/document-flag.js.map +1 -0
- package/dist/document-frame-router.d.ts +245 -0
- package/dist/document-frame-router.d.ts.map +1 -0
- package/dist/document-frame-router.js +397 -0
- package/dist/document-frame-router.js.map +1 -0
- package/dist/document-gate-wiring.d.ts +61 -0
- package/dist/document-gate-wiring.d.ts.map +1 -0
- package/dist/document-gate-wiring.js +125 -0
- package/dist/document-gate-wiring.js.map +1 -0
- package/dist/document-gate.d.ts +149 -0
- package/dist/document-gate.d.ts.map +1 -0
- package/dist/document-gate.js +509 -0
- package/dist/document-gate.js.map +1 -0
- package/dist/document-handlers.d.ts +47 -0
- package/dist/document-handlers.d.ts.map +1 -0
- package/dist/document-handlers.js +2203 -0
- package/dist/document-handlers.js.map +1 -0
- package/dist/document-handshake.d.ts +176 -0
- package/dist/document-handshake.d.ts.map +1 -0
- package/dist/document-handshake.js +452 -0
- package/dist/document-handshake.js.map +1 -0
- package/dist/document-inbound.d.ts +162 -0
- package/dist/document-inbound.d.ts.map +1 -0
- package/dist/document-inbound.js +530 -0
- package/dist/document-inbound.js.map +1 -0
- package/dist/document-json.d.ts +120 -0
- package/dist/document-json.d.ts.map +1 -0
- package/dist/document-json.js +191 -0
- package/dist/document-json.js.map +1 -0
- package/dist/document-layer.d.ts +215 -0
- package/dist/document-layer.d.ts.map +1 -0
- package/dist/document-layer.js +1025 -0
- package/dist/document-layer.js.map +1 -0
- package/dist/document-lifecycle.d.ts +52 -0
- package/dist/document-lifecycle.d.ts.map +1 -0
- package/dist/document-lifecycle.js +134 -0
- package/dist/document-lifecycle.js.map +1 -0
- package/dist/document-live-docs.d.ts +58 -0
- package/dist/document-live-docs.d.ts.map +1 -0
- package/dist/document-live-docs.js +126 -0
- package/dist/document-live-docs.js.map +1 -0
- package/dist/document-notify.d.ts +228 -0
- package/dist/document-notify.d.ts.map +1 -0
- package/dist/document-notify.js +580 -0
- package/dist/document-notify.js.map +1 -0
- package/dist/document-profile.d.ts +61 -0
- package/dist/document-profile.d.ts.map +1 -0
- package/dist/document-profile.js +112 -0
- package/dist/document-profile.js.map +1 -0
- package/dist/document-publish.d.ts +87 -0
- package/dist/document-publish.d.ts.map +1 -0
- package/dist/document-publish.js +173 -0
- package/dist/document-publish.js.map +1 -0
- package/dist/document-reachability.d.ts +42 -0
- package/dist/document-reachability.d.ts.map +1 -0
- package/dist/document-reachability.js +80 -0
- package/dist/document-reachability.js.map +1 -0
- package/dist/document-reconcile-engine.d.ts +66 -0
- package/dist/document-reconcile-engine.d.ts.map +1 -0
- package/dist/document-reconcile-engine.js +225 -0
- package/dist/document-reconcile-engine.js.map +1 -0
- package/dist/document-reconcile-scheduler.d.ts +163 -0
- package/dist/document-reconcile-scheduler.d.ts.map +1 -0
- package/dist/document-reconcile-scheduler.js +303 -0
- package/dist/document-reconcile-scheduler.js.map +1 -0
- package/dist/document-rejection.d.ts +251 -0
- package/dist/document-rejection.d.ts.map +1 -0
- package/dist/document-rejection.js +435 -0
- package/dist/document-rejection.js.map +1 -0
- package/dist/document-screen.d.ts +114 -0
- package/dist/document-screen.d.ts.map +1 -0
- package/dist/document-screen.js +223 -0
- package/dist/document-screen.js.map +1 -0
- package/dist/document-store.d.ts +372 -0
- package/dist/document-store.d.ts.map +1 -0
- package/dist/document-store.js +931 -0
- package/dist/document-store.js.map +1 -0
- package/dist/document-surface.d.ts +32 -0
- package/dist/document-surface.d.ts.map +1 -0
- package/dist/document-surface.js +151 -0
- package/dist/document-surface.js.map +1 -0
- package/dist/document-types.d.ts +94 -0
- package/dist/document-types.d.ts.map +1 -0
- package/dist/document-types.js +90 -0
- package/dist/document-types.js.map +1 -0
- package/dist/document-watch.d.ts +69 -0
- package/dist/document-watch.d.ts.map +1 -0
- package/dist/document-watch.js +108 -0
- package/dist/document-watch.js.map +1 -0
- package/dist/document-wiring.d.ts +53 -0
- package/dist/document-wiring.d.ts.map +1 -0
- package/dist/document-wiring.js +323 -0
- package/dist/document-wiring.js.map +1 -0
- package/dist/document-write-guard.d.ts +66 -0
- package/dist/document-write-guard.d.ts.map +1 -0
- package/dist/document-write-guard.js +98 -0
- package/dist/document-write-guard.js.map +1 -0
- package/dist/document-write-path.d.ts +94 -0
- package/dist/document-write-path.d.ts.map +1 -0
- package/dist/document-write-path.js +530 -0
- package/dist/document-write-path.js.map +1 -0
- package/dist/error-message.d.ts +7 -0
- package/dist/error-message.d.ts.map +1 -0
- package/dist/error-message.js +19 -0
- package/dist/error-message.js.map +1 -0
- package/dist/file-manifest-provider.d.ts +37 -0
- package/dist/file-manifest-provider.d.ts.map +1 -0
- package/dist/file-manifest-provider.js +105 -0
- package/dist/file-manifest-provider.js.map +1 -0
- package/dist/frame-values.d.ts +3 -0
- package/dist/frame-values.d.ts.map +1 -0
- package/dist/frame-values.js +84 -0
- package/dist/frame-values.js.map +1 -0
- package/dist/frontier-mismatch.d.ts +73 -0
- package/dist/frontier-mismatch.d.ts.map +1 -0
- package/dist/frontier-mismatch.js +89 -0
- package/dist/frontier-mismatch.js.map +1 -0
- package/dist/gateway-config-handlers.d.ts +26 -0
- package/dist/gateway-config-handlers.d.ts.map +1 -0
- package/dist/gateway-config-handlers.js +454 -0
- package/dist/gateway-config-handlers.js.map +1 -0
- package/dist/held-content.d.ts +145 -0
- package/dist/held-content.d.ts.map +1 -0
- package/dist/held-content.js +389 -0
- package/dist/held-content.js.map +1 -0
- package/dist/http-manifest-poll.d.ts +67 -0
- package/dist/http-manifest-poll.d.ts.map +1 -0
- package/dist/http-manifest-poll.js +150 -0
- package/dist/http-manifest-poll.js.map +1 -0
- package/dist/identity-migration.d.ts +40 -0
- package/dist/identity-migration.d.ts.map +1 -0
- package/dist/identity-migration.js +461 -0
- package/dist/identity-migration.js.map +1 -0
- package/dist/inbound-refusals.d.ts +283 -0
- package/dist/inbound-refusals.d.ts.map +1 -0
- package/dist/inbound-refusals.js +919 -0
- package/dist/inbound-refusals.js.map +1 -0
- package/dist/inbound-seal-request.d.ts +32 -0
- package/dist/inbound-seal-request.d.ts.map +1 -0
- package/dist/inbound-seal-request.js +228 -0
- package/dist/inbound-seal-request.js.map +1 -0
- package/dist/inbound-sessions.d.ts +291 -0
- package/dist/inbound-sessions.d.ts.map +1 -0
- package/dist/inbound-sessions.js +1609 -0
- package/dist/inbound-sessions.js.map +1 -0
- package/dist/inclusion-proof-handlers.d.ts +43 -0
- package/dist/inclusion-proof-handlers.d.ts.map +1 -0
- package/dist/inclusion-proof-handlers.js +565 -0
- package/dist/inclusion-proof-handlers.js.map +1 -0
- package/dist/inclusion-proof.d.ts +151 -0
- package/dist/inclusion-proof.d.ts.map +1 -0
- package/dist/inclusion-proof.js +228 -0
- package/dist/inclusion-proof.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/initiate-session-handler.d.ts +55 -0
- package/dist/initiate-session-handler.d.ts.map +1 -0
- package/dist/initiate-session-handler.js +310 -0
- package/dist/initiate-session-handler.js.map +1 -0
- package/dist/ipc-client.d.ts +31 -0
- package/dist/ipc-client.d.ts.map +1 -0
- package/dist/ipc-client.js +113 -0
- package/dist/ipc-client.js.map +1 -0
- package/dist/ipc-server.d.ts +63 -0
- package/dist/ipc-server.d.ts.map +1 -0
- package/dist/ipc-server.js +429 -0
- package/dist/ipc-server.js.map +1 -0
- package/dist/ipc-surface.d.ts +44 -0
- package/dist/ipc-surface.d.ts.map +1 -0
- package/dist/ipc-surface.js +107 -0
- package/dist/ipc-surface.js.map +1 -0
- package/dist/line-lcs.d.ts +51 -0
- package/dist/line-lcs.d.ts.map +1 -0
- package/dist/line-lcs.js +71 -0
- package/dist/line-lcs.js.map +1 -0
- package/dist/lock-file.d.ts +39 -0
- package/dist/lock-file.d.ts.map +1 -0
- package/dist/lock-file.js +120 -0
- package/dist/lock-file.js.map +1 -0
- package/dist/log-collapse.d.ts +66 -0
- package/dist/log-collapse.d.ts.map +1 -0
- package/dist/log-collapse.js +244 -0
- package/dist/log-collapse.js.map +1 -0
- package/dist/log-rotate.d.ts +67 -0
- package/dist/log-rotate.d.ts.map +1 -0
- package/dist/log-rotate.js +134 -0
- package/dist/log-rotate.js.map +1 -0
- package/dist/manifest-deps.d.ts +25 -0
- package/dist/manifest-deps.d.ts.map +1 -0
- package/dist/manifest-deps.js +151 -0
- package/dist/manifest-deps.js.map +1 -0
- package/dist/manifest-poll-scheduler.d.ts +31 -0
- package/dist/manifest-poll-scheduler.d.ts.map +1 -0
- package/dist/manifest-poll-scheduler.js +59 -0
- package/dist/manifest-poll-scheduler.js.map +1 -0
- package/dist/manifest-validity.d.ts +153 -0
- package/dist/manifest-validity.d.ts.map +1 -0
- package/dist/manifest-validity.js +268 -0
- package/dist/manifest-validity.js.map +1 -0
- package/dist/manifest-version-store-db.d.ts +24 -0
- package/dist/manifest-version-store-db.d.ts.map +1 -0
- package/dist/manifest-version-store-db.js +58 -0
- package/dist/manifest-version-store-db.js.map +1 -0
- package/dist/manifest-version-store.d.ts +16 -0
- package/dist/manifest-version-store.d.ts.map +1 -0
- package/dist/manifest-version-store.js +15 -0
- package/dist/manifest-version-store.js.map +1 -0
- package/dist/network-directory-node.d.ts +136 -0
- package/dist/network-directory-node.d.ts.map +1 -0
- package/dist/network-directory-node.js +810 -0
- package/dist/network-directory-node.js.map +1 -0
- package/dist/nonce-dedup.d.ts +68 -0
- package/dist/nonce-dedup.d.ts.map +1 -0
- package/dist/nonce-dedup.js +205 -0
- package/dist/nonce-dedup.js.map +1 -0
- package/dist/notification-dispatcher.d.ts +92 -0
- package/dist/notification-dispatcher.d.ts.map +1 -0
- package/dist/notification-dispatcher.js +210 -0
- package/dist/notification-dispatcher.js.map +1 -0
- package/dist/notification-handlers.d.ts +53 -0
- package/dist/notification-handlers.d.ts.map +1 -0
- package/dist/notification-handlers.js +461 -0
- package/dist/notification-handlers.js.map +1 -0
- package/dist/onboarding-guidance.d.ts +79 -0
- package/dist/onboarding-guidance.d.ts.map +1 -0
- package/dist/onboarding-guidance.js +95 -0
- package/dist/onboarding-guidance.js.map +1 -0
- package/dist/operator-guidance.d.ts +25 -0
- package/dist/operator-guidance.d.ts.map +1 -0
- package/dist/operator-guidance.js +50 -0
- package/dist/operator-guidance.js.map +1 -0
- package/dist/orphan-triage.d.ts +130 -0
- package/dist/orphan-triage.d.ts.map +1 -0
- package/dist/orphan-triage.js +207 -0
- package/dist/orphan-triage.js.map +1 -0
- package/dist/outbound-sessions.d.ts +126 -0
- package/dist/outbound-sessions.d.ts.map +1 -0
- package/dist/outbound-sessions.js +1052 -0
- package/dist/outbound-sessions.js.map +1 -0
- package/dist/park-envelope.d.ts +329 -0
- package/dist/park-envelope.d.ts.map +1 -0
- package/dist/park-envelope.js +509 -0
- package/dist/park-envelope.js.map +1 -0
- package/dist/park-recovery.d.ts +273 -0
- package/dist/park-recovery.d.ts.map +1 -0
- package/dist/park-recovery.js +717 -0
- package/dist/park-recovery.js.map +1 -0
- package/dist/park-refusals.d.ts +147 -0
- package/dist/park-refusals.d.ts.map +1 -0
- package/dist/park-refusals.js +331 -0
- package/dist/park-refusals.js.map +1 -0
- package/dist/quarantine-framing.d.ts +92 -0
- package/dist/quarantine-framing.d.ts.map +1 -0
- package/dist/quarantine-framing.js +111 -0
- package/dist/quarantine-framing.js.map +1 -0
- package/dist/reconnect-drain.d.ts +22 -0
- package/dist/reconnect-drain.d.ts.map +1 -0
- package/dist/reconnect-drain.js +65 -0
- package/dist/reconnect-drain.js.map +1 -0
- package/dist/recovered-position.d.ts +14 -0
- package/dist/recovered-position.d.ts.map +1 -0
- package/dist/recovered-position.js +59 -0
- package/dist/recovered-position.js.map +1 -0
- package/dist/refusal-notices.d.ts +196 -0
- package/dist/refusal-notices.d.ts.map +1 -0
- package/dist/refusal-notices.js +516 -0
- package/dist/refusal-notices.js.map +1 -0
- package/dist/refusal-reasons.d.ts +245 -0
- package/dist/refusal-reasons.d.ts.map +1 -0
- package/dist/refusal-reasons.js +363 -0
- package/dist/refusal-reasons.js.map +1 -0
- package/dist/register-handler.d.ts +36 -0
- package/dist/register-handler.d.ts.map +1 -0
- package/dist/register-handler.js +285 -0
- package/dist/register-handler.js.map +1 -0
- package/dist/registration-context.d.ts +72 -0
- package/dist/registration-context.d.ts.map +1 -0
- package/dist/registration-context.js +126 -0
- package/dist/registration-context.js.map +1 -0
- package/dist/registration-manager.d.ts +94 -0
- package/dist/registration-manager.d.ts.map +1 -0
- package/dist/registration-manager.js +585 -0
- package/dist/registration-manager.js.map +1 -0
- package/dist/registration-persistence.d.ts +183 -0
- package/dist/registration-persistence.d.ts.map +1 -0
- package/dist/registration-persistence.js +263 -0
- package/dist/registration-persistence.js.map +1 -0
- package/dist/registry-poll.d.ts +52 -0
- package/dist/registry-poll.d.ts.map +1 -0
- package/dist/registry-poll.js +140 -0
- package/dist/registry-poll.js.map +1 -0
- package/dist/registry-version-store-db.d.ts +22 -0
- package/dist/registry-version-store-db.d.ts.map +1 -0
- package/dist/registry-version-store-db.js +50 -0
- package/dist/registry-version-store-db.js.map +1 -0
- package/dist/relay-endpoints.d.ts +18 -0
- package/dist/relay-endpoints.d.ts.map +1 -0
- package/dist/relay-endpoints.js +9 -0
- package/dist/relay-endpoints.js.map +1 -0
- package/dist/relay-only.d.ts +140 -0
- package/dist/relay-only.d.ts.map +1 -0
- package/dist/relay-only.js +193 -0
- package/dist/relay-only.js.map +1 -0
- package/dist/relay-receipt-store.d.ts +155 -0
- package/dist/relay-receipt-store.d.ts.map +1 -0
- package/dist/relay-receipt-store.js +284 -0
- package/dist/relay-receipt-store.js.map +1 -0
- package/dist/relay-reconnect.d.ts +32 -0
- package/dist/relay-reconnect.d.ts.map +1 -0
- package/dist/relay-reconnect.js +29 -0
- package/dist/relay-reconnect.js.map +1 -0
- package/dist/reply-lag.d.ts +11 -0
- package/dist/reply-lag.d.ts.map +1 -0
- package/dist/reply-lag.js +46 -0
- package/dist/reply-lag.js.map +1 -0
- package/dist/resolve-named-agent.d.ts +49 -0
- package/dist/resolve-named-agent.d.ts.map +1 -0
- package/dist/resolve-named-agent.js +77 -0
- package/dist/resolve-named-agent.js.map +1 -0
- package/dist/restart-seal-resolver.d.ts +110 -0
- package/dist/restart-seal-resolver.d.ts.map +1 -0
- package/dist/restart-seal-resolver.js +353 -0
- package/dist/restart-seal-resolver.js.map +1 -0
- package/dist/resume-last-seen.d.ts +15 -0
- package/dist/resume-last-seen.d.ts.map +1 -0
- package/dist/resume-last-seen.js +44 -0
- package/dist/resume-last-seen.js.map +1 -0
- package/dist/retry-queue.d.ts +203 -0
- package/dist/retry-queue.d.ts.map +1 -0
- package/dist/retry-queue.js +701 -0
- package/dist/retry-queue.js.map +1 -0
- package/dist/roster-freshness.d.ts +160 -0
- package/dist/roster-freshness.d.ts.map +1 -0
- package/dist/roster-freshness.js +250 -0
- package/dist/roster-freshness.js.map +1 -0
- package/dist/screening-status.d.ts +15 -0
- package/dist/screening-status.d.ts.map +1 -0
- package/dist/screening-status.js +65 -0
- package/dist/screening-status.js.map +1 -0
- package/dist/seal-carried-close.d.ts +37 -0
- package/dist/seal-carried-close.d.ts.map +1 -0
- package/dist/seal-carried-close.js +179 -0
- package/dist/seal-carried-close.js.map +1 -0
- package/dist/seal-certificate-pull.d.ts +79 -0
- package/dist/seal-certificate-pull.d.ts.map +1 -0
- package/dist/seal-certificate-pull.js +186 -0
- package/dist/seal-certificate-pull.js.map +1 -0
- package/dist/seal-certified-root-check.d.ts +37 -0
- package/dist/seal-certified-root-check.d.ts.map +1 -0
- package/dist/seal-certified-root-check.js +127 -0
- package/dist/seal-certified-root-check.js.map +1 -0
- package/dist/seal-coordinator.d.ts +118 -0
- package/dist/seal-coordinator.d.ts.map +1 -0
- package/dist/seal-coordinator.js +927 -0
- package/dist/seal-coordinator.js.map +1 -0
- package/dist/seal-escalation.d.ts +80 -0
- package/dist/seal-escalation.d.ts.map +1 -0
- package/dist/seal-escalation.js +283 -0
- package/dist/seal-escalation.js.map +1 -0
- package/dist/seal-evidence-root-check.d.ts +70 -0
- package/dist/seal-evidence-root-check.d.ts.map +1 -0
- package/dist/seal-evidence-root-check.js +199 -0
- package/dist/seal-evidence-root-check.js.map +1 -0
- package/dist/seal-failure-store.d.ts +139 -0
- package/dist/seal-failure-store.d.ts.map +1 -0
- package/dist/seal-failure-store.js +207 -0
- package/dist/seal-failure-store.js.map +1 -0
- package/dist/seal-flows.d.ts +107 -0
- package/dist/seal-flows.d.ts.map +1 -0
- package/dist/seal-flows.js +638 -0
- package/dist/seal-flows.js.map +1 -0
- package/dist/seal-frontier-verify.d.ts +103 -0
- package/dist/seal-frontier-verify.d.ts.map +1 -0
- package/dist/seal-frontier-verify.js +143 -0
- package/dist/seal-frontier-verify.js.map +1 -0
- package/dist/seal-leaf.d.ts +58 -0
- package/dist/seal-leaf.d.ts.map +1 -0
- package/dist/seal-leaf.js +112 -0
- package/dist/seal-leaf.js.map +1 -0
- package/dist/seal-legibility-tbs.d.ts +25 -0
- package/dist/seal-legibility-tbs.d.ts.map +1 -0
- package/dist/seal-legibility-tbs.js +77 -0
- package/dist/seal-legibility-tbs.js.map +1 -0
- package/dist/seal-local-terminus.d.ts +41 -0
- package/dist/seal-local-terminus.d.ts.map +1 -0
- package/dist/seal-local-terminus.js +170 -0
- package/dist/seal-local-terminus.js.map +1 -0
- package/dist/seal-receipt-upgrade.d.ts +30 -0
- package/dist/seal-receipt-upgrade.d.ts.map +1 -0
- package/dist/seal-receipt-upgrade.js +49 -0
- package/dist/seal-receipt-upgrade.js.map +1 -0
- package/dist/seal-relay-silence.d.ts +51 -0
- package/dist/seal-relay-silence.d.ts.map +1 -0
- package/dist/seal-relay-silence.js +76 -0
- package/dist/seal-relay-silence.js.map +1 -0
- package/dist/seal-settle.d.ts +38 -0
- package/dist/seal-settle.d.ts.map +1 -0
- package/dist/seal-settle.js +33 -0
- package/dist/seal-settle.js.map +1 -0
- package/dist/seal-upgrade.d.ts +107 -0
- package/dist/seal-upgrade.d.ts.map +1 -0
- package/dist/seal-upgrade.js +200 -0
- package/dist/seal-upgrade.js.map +1 -0
- package/dist/sealed-conversation.d.ts +36 -0
- package/dist/sealed-conversation.d.ts.map +1 -0
- package/dist/sealed-conversation.js +171 -0
- package/dist/sealed-conversation.js.map +1 -0
- package/dist/sealed-leaf-set.d.ts +92 -0
- package/dist/sealed-leaf-set.d.ts.map +1 -0
- package/dist/sealed-leaf-set.js +122 -0
- package/dist/sealed-leaf-set.js.map +1 -0
- package/dist/send-claims.d.ts +56 -0
- package/dist/send-claims.d.ts.map +1 -0
- package/dist/send-claims.js +50 -0
- package/dist/send-claims.js.map +1 -0
- package/dist/session-assignment-parser.d.ts +104 -0
- package/dist/session-assignment-parser.d.ts.map +1 -0
- package/dist/session-assignment-parser.js +345 -0
- package/dist/session-assignment-parser.js.map +1 -0
- package/dist/session-category.d.ts +19 -0
- package/dist/session-category.d.ts.map +1 -0
- package/dist/session-category.js +14 -0
- package/dist/session-category.js.map +1 -0
- package/dist/session-ceremony.d.ts +297 -0
- package/dist/session-ceremony.d.ts.map +1 -0
- package/dist/session-ceremony.js +964 -0
- package/dist/session-ceremony.js.map +1 -0
- package/dist/session-closed.d.ts +79 -0
- package/dist/session-closed.d.ts.map +1 -0
- package/dist/session-closed.js +189 -0
- package/dist/session-closed.js.map +1 -0
- package/dist/session-connection-gater.d.ts +148 -0
- package/dist/session-connection-gater.d.ts.map +1 -0
- package/dist/session-connection-gater.js +332 -0
- package/dist/session-connection-gater.js.map +1 -0
- package/dist/session-content-context.d.ts +162 -0
- package/dist/session-content-context.d.ts.map +1 -0
- package/dist/session-content-context.js +2 -0
- package/dist/session-content-context.js.map +1 -0
- package/dist/session-content-handlers.d.ts +82 -0
- package/dist/session-content-handlers.d.ts.map +1 -0
- package/dist/session-content-handlers.js +1382 -0
- package/dist/session-content-handlers.js.map +1 -0
- package/dist/session-content-ingest.d.ts +206 -0
- package/dist/session-content-ingest.d.ts.map +1 -0
- package/dist/session-content-ingest.js +2167 -0
- package/dist/session-content-ingest.js.map +1 -0
- package/dist/session-content-send.d.ts +191 -0
- package/dist/session-content-send.d.ts.map +1 -0
- package/dist/session-content-send.js +1360 -0
- package/dist/session-content-send.js.map +1 -0
- package/dist/session-delivery-acks.d.ts +169 -0
- package/dist/session-delivery-acks.d.ts.map +1 -0
- package/dist/session-delivery-acks.js +569 -0
- package/dist/session-delivery-acks.js.map +1 -0
- package/dist/session-ephemerals.d.ts +279 -0
- package/dist/session-ephemerals.d.ts.map +1 -0
- package/dist/session-ephemerals.js +591 -0
- package/dist/session-ephemerals.js.map +1 -0
- package/dist/session-leaf-records.d.ts +159 -0
- package/dist/session-leaf-records.d.ts.map +1 -0
- package/dist/session-leaf-records.js +408 -0
- package/dist/session-leaf-records.js.map +1 -0
- package/dist/session-lifecycle.d.ts +303 -0
- package/dist/session-lifecycle.d.ts.map +1 -0
- package/dist/session-lifecycle.js +1679 -0
- package/dist/session-lifecycle.js.map +1 -0
- package/dist/session-liveness.d.ts +135 -0
- package/dist/session-liveness.d.ts.map +1 -0
- package/dist/session-liveness.js +347 -0
- package/dist/session-liveness.js.map +1 -0
- package/dist/session-name.d.ts +35 -0
- package/dist/session-name.d.ts.map +1 -0
- package/dist/session-name.js +60 -0
- package/dist/session-name.js.map +1 -0
- package/dist/session-node-factory.d.ts +18 -0
- package/dist/session-node-factory.d.ts.map +1 -0
- package/dist/session-node-factory.js +182 -0
- package/dist/session-node-factory.js.map +1 -0
- package/dist/session-node-manager.d.ts +877 -0
- package/dist/session-node-manager.d.ts.map +1 -0
- package/dist/session-node-manager.js +2998 -0
- package/dist/session-node-manager.js.map +1 -0
- package/dist/session-node-types.d.ts +1057 -0
- package/dist/session-node-types.d.ts.map +1 -0
- package/dist/session-node-types.js +657 -0
- package/dist/session-node-types.js.map +1 -0
- package/dist/session-notify.d.ts +46 -0
- package/dist/session-notify.d.ts.map +1 -0
- package/dist/session-notify.js +116 -0
- package/dist/session-notify.js.map +1 -0
- package/dist/session-own-chain-store.d.ts +65 -0
- package/dist/session-own-chain-store.d.ts.map +1 -0
- package/dist/session-own-chain-store.js +75 -0
- package/dist/session-own-chain-store.js.map +1 -0
- package/dist/session-queries.d.ts +476 -0
- package/dist/session-queries.d.ts.map +1 -0
- package/dist/session-queries.js +1007 -0
- package/dist/session-queries.js.map +1 -0
- package/dist/session-read-handlers.d.ts +87 -0
- package/dist/session-read-handlers.d.ts.map +1 -0
- package/dist/session-read-handlers.js +689 -0
- package/dist/session-read-handlers.js.map +1 -0
- package/dist/session-records.d.ts +341 -0
- package/dist/session-records.d.ts.map +1 -0
- package/dist/session-records.js +858 -0
- package/dist/session-records.js.map +1 -0
- package/dist/session-relay-client.d.ts +659 -0
- package/dist/session-relay-client.d.ts.map +1 -0
- package/dist/session-relay-client.js +2876 -0
- package/dist/session-relay-client.js.map +1 -0
- package/dist/session-relay.d.ts +397 -0
- package/dist/session-relay.d.ts.map +1 -0
- package/dist/session-relay.js +1636 -0
- package/dist/session-relay.js.map +1 -0
- package/dist/session-salt-agreement.d.ts +331 -0
- package/dist/session-salt-agreement.d.ts.map +1 -0
- package/dist/session-salt-agreement.js +472 -0
- package/dist/session-salt-agreement.js.map +1 -0
- package/dist/session-salts.d.ts +432 -0
- package/dist/session-salts.d.ts.map +1 -0
- package/dist/session-salts.js +1540 -0
- package/dist/session-salts.js.map +1 -0
- package/dist/session-schema.d.ts +30 -0
- package/dist/session-schema.d.ts.map +1 -0
- package/dist/session-schema.js +877 -0
- package/dist/session-schema.js.map +1 -0
- package/dist/session-seal-leaf-store.d.ts +70 -0
- package/dist/session-seal-leaf-store.d.ts.map +1 -0
- package/dist/session-seal-leaf-store.js +105 -0
- package/dist/session-seal-leaf-store.js.map +1 -0
- package/dist/session-seal.d.ts +334 -0
- package/dist/session-seal.d.ts.map +1 -0
- package/dist/session-seal.js +1017 -0
- package/dist/session-seal.js.map +1 -0
- package/dist/session-terminal-refusal.d.ts +65 -0
- package/dist/session-terminal-refusal.d.ts.map +1 -0
- package/dist/session-terminal-refusal.js +87 -0
- package/dist/session-terminal-refusal.js.map +1 -0
- package/dist/session-tree.d.ts +110 -0
- package/dist/session-tree.d.ts.map +1 -0
- package/dist/session-tree.js +144 -0
- package/dist/session-tree.js.map +1 -0
- package/dist/session-views.d.ts +47 -0
- package/dist/session-views.d.ts.map +1 -0
- package/dist/session-views.js +278 -0
- package/dist/session-views.js.map +1 -0
- package/dist/signal-handlers.d.ts +63 -0
- package/dist/signal-handlers.d.ts.map +1 -0
- package/dist/signal-handlers.js +980 -0
- package/dist/signal-handlers.js.map +1 -0
- package/dist/signal-requirement-policy.d.ts +51 -0
- package/dist/signal-requirement-policy.d.ts.map +1 -0
- package/dist/signal-requirement-policy.js +89 -0
- package/dist/signal-requirement-policy.js.map +1 -0
- package/dist/signal-revocability.d.ts +49 -0
- package/dist/signal-revocability.d.ts.map +1 -0
- package/dist/signal-revocability.js +93 -0
- package/dist/signal-revocability.js.map +1 -0
- package/dist/signal-submission.d.ts +181 -0
- package/dist/signal-submission.d.ts.map +1 -0
- package/dist/signal-submission.js +368 -0
- package/dist/signal-submission.js.map +1 -0
- package/dist/signaling-connect.d.ts +118 -0
- package/dist/signaling-connect.d.ts.map +1 -0
- package/dist/signaling-connect.js +538 -0
- package/dist/signaling-connect.js.map +1 -0
- package/dist/signaling-wiring.d.ts +105 -0
- package/dist/signaling-wiring.d.ts.map +1 -0
- package/dist/signaling-wiring.js +393 -0
- package/dist/signaling-wiring.js.map +1 -0
- package/dist/singleton-lock.d.ts +85 -0
- package/dist/singleton-lock.d.ts.map +1 -0
- package/dist/singleton-lock.js +219 -0
- package/dist/singleton-lock.js.map +1 -0
- package/dist/sqlcipher-db.d.ts +139 -0
- package/dist/sqlcipher-db.d.ts.map +1 -0
- package/dist/sqlcipher-db.js +357 -0
- package/dist/sqlcipher-db.js.map +1 -0
- package/dist/standing-receivers.d.ts +319 -0
- package/dist/standing-receivers.d.ts.map +1 -0
- package/dist/standing-receivers.js +1295 -0
- package/dist/standing-receivers.js.map +1 -0
- package/dist/start-agent.d.ts +64 -0
- package/dist/start-agent.d.ts.map +1 -0
- package/dist/start-agent.js +136 -0
- package/dist/start-agent.js.map +1 -0
- package/dist/status-handler.d.ts +54 -0
- package/dist/status-handler.d.ts.map +1 -0
- package/dist/status-handler.js +61 -0
- package/dist/status-handler.js.map +1 -0
- package/dist/submission-retry.d.ts +208 -0
- package/dist/submission-retry.d.ts.map +1 -0
- package/dist/submission-retry.js +506 -0
- package/dist/submission-retry.js.map +1 -0
- package/dist/telegram-bot-client.d.ts +34 -0
- package/dist/telegram-bot-client.d.ts.map +1 -0
- package/dist/telegram-bot-client.js +36 -0
- package/dist/telegram-bot-client.js.map +1 -0
- package/dist/telegram-doorbell.d.ts +38 -0
- package/dist/telegram-doorbell.d.ts.map +1 -0
- package/dist/telegram-doorbell.js +140 -0
- package/dist/telegram-doorbell.js.map +1 -0
- package/dist/test-handlers.d.ts +62 -0
- package/dist/test-handlers.d.ts.map +1 -0
- package/dist/test-handlers.js +240 -0
- package/dist/test-handlers.js.map +1 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +10 -0
- package/dist/testing.js.map +1 -0
- package/dist/transport-composition.d.ts +31 -0
- package/dist/transport-composition.d.ts.map +1 -0
- package/dist/transport-composition.js +55 -0
- package/dist/transport-composition.js.map +1 -0
- package/dist/transport-selector.d.ts +202 -0
- package/dist/transport-selector.d.ts.map +1 -0
- package/dist/transport-selector.js +196 -0
- package/dist/transport-selector.js.map +1 -0
- package/dist/trust-signal-pickup-listener.d.ts +43 -0
- package/dist/trust-signal-pickup-listener.d.ts.map +1 -0
- package/dist/trust-signal-pickup-listener.js +48 -0
- package/dist/trust-signal-pickup-listener.js.map +1 -0
- package/dist/trust-signal-store.d.ts +406 -0
- package/dist/trust-signal-store.d.ts.map +1 -0
- package/dist/trust-signal-store.js +939 -0
- package/dist/trust-signal-store.js.map +1 -0
- package/dist/trust-signal-sweep-tick.d.ts +60 -0
- package/dist/trust-signal-sweep-tick.d.ts.map +1 -0
- package/dist/trust-signal-sweep-tick.js +101 -0
- package/dist/trust-signal-sweep-tick.js.map +1 -0
- package/dist/trust-signal-sweep.d.ts +94 -0
- package/dist/trust-signal-sweep.d.ts.map +1 -0
- package/dist/trust-signal-sweep.js +147 -0
- package/dist/trust-signal-sweep.js.map +1 -0
- package/dist/type-registry.d.ts +42 -0
- package/dist/type-registry.d.ts.map +1 -0
- package/dist/type-registry.js +37 -0
- package/dist/type-registry.js.map +1 -0
- package/dist/types.d.ts +746 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/unresolved-nodes-report.d.ts +14 -0
- package/dist/unresolved-nodes-report.d.ts.map +1 -0
- package/dist/unresolved-nodes-report.js +96 -0
- package/dist/unresolved-nodes-report.js.map +1 -0
- package/dist/vocabulary.d.ts +150 -0
- package/dist/vocabulary.d.ts.map +1 -0
- package/dist/vocabulary.js +386 -0
- package/dist/vocabulary.js.map +1 -0
- package/dist/who-label.d.ts +28 -0
- package/dist/who-label.d.ts.map +1 -0
- package/dist/who-label.js +31 -0
- package/dist/who-label.js.map +1 -0
- package/dist/who-resolver.d.ts +15 -0
- package/dist/who-resolver.d.ts.map +1 -0
- package/dist/who-resolver.js +47 -0
- package/dist/who-resolver.js.map +1 -0
- package/dist/wire-content-hash.d.ts +93 -0
- package/dist/wire-content-hash.d.ts.map +1 -0
- package/dist/wire-content-hash.js +116 -0
- package/dist/wire-content-hash.js.map +1 -0
- package/dist/withheld-content.d.ts +13 -0
- package/dist/withheld-content.d.ts.map +1 -0
- package/dist/withheld-content.js +46 -0
- package/dist/withheld-content.js.map +1 -0
- package/dist/witness-alerts.d.ts +40 -0
- package/dist/witness-alerts.d.ts.map +1 -0
- package/dist/witness-alerts.js +102 -0
- package/dist/witness-alerts.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-signing FROST ceremony participation — daemon side (DOD-SPINE-5, increment 3).
|
|
3
|
+
*
|
|
4
|
+
* When an initiator's `cello_initiate_session` reaches the directory, the directory
|
|
5
|
+
* FROST-signs the SessionAssignment by DELEGATING to the initiator: its
|
|
6
|
+
* `ClientDelegatedSigner.participateInCeremony` sends a `ceremony_request`
|
|
7
|
+
* {ceremony_id, tbs, context} over the initiator's authenticated signaling stream and
|
|
8
|
+
* awaits a `ceremony_result` {ceremony_id, signature}. The initiator (coordinator) runs
|
|
9
|
+
* the FROST ceremony with its share + the directory's K_server_X shares, and replies.
|
|
10
|
+
*
|
|
11
|
+
* This wires that handler onto a PER-AGENT signaling stream (the same per-agent routing used for
|
|
12
|
+
* registration).
|
|
13
|
+
*
|
|
14
|
+
* The threshold signer is reconstructed lazily from the agent's persisted
|
|
15
|
+
* `frost-share.json` (the daemon holds no FrostThresholdSigner after registration —
|
|
16
|
+
* the registration-time signer was on the disposed RegistrationContext).
|
|
17
|
+
*/
|
|
18
|
+
import { decode } from "cbor-x";
|
|
19
|
+
import { encodeCbor } from "@cello-protocol/protocol-types";
|
|
20
|
+
import { createHash } from "node:crypto";
|
|
21
|
+
import { buildSealTbs } from "@cello-protocol/protocol-types";
|
|
22
|
+
import { bindLegibilityToTbs } from "./seal-legibility-tbs.js";
|
|
23
|
+
import { reDeriveFrontiers, findInflatedFrontier } from "./seal-frontier-verify.js";
|
|
24
|
+
import { FrostThresholdSigner } from "@cello-protocol/crypto";
|
|
25
|
+
import { storeDkgResult } from "@cello-protocol/crypto/frost/frost-threshold-signer.js";
|
|
26
|
+
import { NetworkDirectoryNode, runNetworkRefresh } from "./network-directory-node.js";
|
|
27
|
+
import { extractErrorMessage } from "./error-message.js";
|
|
28
|
+
/**
|
|
29
|
+
* WIRE-002: answer the directory's `session_offer` on a per-agent signaling stream. When an
|
|
30
|
+
* initiator's session_request names this agent as the target, the directory sends a
|
|
31
|
+
* `session_offer {session_id}` before it builds the FROST-signed assignment; the agent must
|
|
32
|
+
* reply `session_offer_accept` advertising its SESSION endpoint (its standing receiver, which
|
|
33
|
+
* `acceptSession` reuses as the receiver-side session node) so the directory can fold the
|
|
34
|
+
* counterparty endpoint into the assignment and the initiator can reach it. Without this, the
|
|
35
|
+
* assignment carries an empty counterparty endpoint and content delivery can never connect.
|
|
36
|
+
*/
|
|
37
|
+
export function wireSessionOfferHandler(deps) {
|
|
38
|
+
// DOD-OFFER-REJECT-1 (D1): answer, never vanish. A silent abort left the directory waiting
|
|
39
|
+
// 2 s for an accept that would never come, after which it FROST-signed an assignment with an
|
|
40
|
+
// EMPTY counterparty endpoint and pushed it to both parties — the phantom session's origin.
|
|
41
|
+
// The reject lets the directory fail fast (D2 resolves its waiter on this frame; until the
|
|
42
|
+
// directory understands it, the frame is inert and the timeout path still applies). This is
|
|
43
|
+
// the Generic Reject of the inbound-state matrix, arriving as a protocol necessity.
|
|
44
|
+
// session_id is echoed when present; a no_session_id offer has nothing to echo, so the field
|
|
45
|
+
// is omitted (never an empty value on the wire — same rule as the directory's encoder).
|
|
46
|
+
async function sendOfferReject(sessionId, reason) {
|
|
47
|
+
const rejectFrame = { type: "session_offer_reject", reason };
|
|
48
|
+
if (sessionId)
|
|
49
|
+
rejectFrame["session_id"] = sessionId;
|
|
50
|
+
try {
|
|
51
|
+
// The production seam (transport SignalingManager.sendRaw) NEVER throws — it resolves
|
|
52
|
+
// {ok:false, reason} on every failure (reconnecting, lost, stream throw). Discarding the
|
|
53
|
+
// result would log reject.sent while nothing left the machine (D1 review F1). The catch
|
|
54
|
+
// stays as belt-and-braces for a seam that does throw.
|
|
55
|
+
const res = await deps.signaling.sendRaw(rejectFrame);
|
|
56
|
+
if (res.ok) {
|
|
57
|
+
deps.logger.info("session.offer.reject.sent", { agentName: deps.agentName, reason });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
deps.logger.warn("session.offer.reject.failed", {
|
|
61
|
+
agentName: deps.agentName,
|
|
62
|
+
reason,
|
|
63
|
+
detail: res.reason ?? "send_not_ok",
|
|
64
|
+
...(res.guidance ? { guidance: res.guidance } : {}),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
deps.logger.warn("session.offer.reject.failed", {
|
|
70
|
+
agentName: deps.agentName,
|
|
71
|
+
reason,
|
|
72
|
+
detail: extractErrorMessage(err),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return deps.signaling.registerInboundHandler((frame) => {
|
|
77
|
+
if (frame["type"] !== "session_offer")
|
|
78
|
+
return;
|
|
79
|
+
void (async () => {
|
|
80
|
+
const sidRaw = frame["session_id"];
|
|
81
|
+
const sessionId = sidRaw instanceof Uint8Array ? sidRaw : Buffer.isBuffer(sidRaw) ? new Uint8Array(sidRaw) : null;
|
|
82
|
+
if (!sessionId) {
|
|
83
|
+
deps.logger.warn("session.offer.abort", { agentName: deps.agentName, reason: "no_session_id" });
|
|
84
|
+
await sendOfferReject(null, "no_session_id");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* M16: A CHANNEL NEVER CONVERSES — and it says so BEFORE it gives anything away. Accepting here
|
|
89
|
+
* would take a relay reservation and send the caller this agent's session peer id and
|
|
90
|
+
* addresses, all for a session the verified assignment is then refused over. The offer is
|
|
91
|
+
* unauthenticated, but this question is about the LOCAL agent only, so a forged offer can do
|
|
92
|
+
* no more than trigger a refusal that was coming anyway. The assignment gate in
|
|
93
|
+
* inbound-sessions.ts stays as the authenticated line.
|
|
94
|
+
*/
|
|
95
|
+
if (deps.isChannelAgent()) {
|
|
96
|
+
deps.logger.warn("session.offer.abort", { agentName: deps.agentName, reason: "channel_identity" });
|
|
97
|
+
await sendOfferReject(sessionId, "channel_identity");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
let sr = deps.getStandingReceiverEndpoint();
|
|
101
|
+
if (!sr) {
|
|
102
|
+
deps.logger.warn("session.offer.abort", { agentName: deps.agentName, reason: "standing_receiver_unavailable" });
|
|
103
|
+
await sendOfferReject(sessionId, "standing_receiver_unavailable");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 055-ONDEMAND — **RESERVE NOW, BECAUSE AN IDLE AGENT HOLDS NOTHING.**
|
|
108
|
+
*
|
|
109
|
+
* This is the whole of the capacity change, seen from the receiving end. The agent no longer
|
|
110
|
+
* carries a slot on every relay against the chance that somebody calls; it takes ONE, on the
|
|
111
|
+
* relay this offer names, at the moment somebody does. The accept below then advertises the
|
|
112
|
+
* circuit address that came back.
|
|
113
|
+
*
|
|
114
|
+
* ⚠️ **THE RELAY IS THE DIRECTORY'S CHOICE, NOT OURS.** The assignment the relay will check
|
|
115
|
+
* names the same relay, from the same variable on the directory's side. Reserving on one we
|
|
116
|
+
* picked ourselves would leave us holding a slot the relay will not route through.
|
|
117
|
+
*
|
|
118
|
+
* ⚠️ **A FAILURE HERE IS NOT FATAL BY ITSELF.** Without a circuit we are still reachable by a
|
|
119
|
+
* peer that can dial us directly; it is relay-only that turns this into a refusal, and that
|
|
120
|
+
* check is deliberately BELOW this line rather than above it — see its own note.
|
|
121
|
+
*/
|
|
122
|
+
const offeredRelay = frame["relay_endpoint"];
|
|
123
|
+
const relayPeerId = typeof offeredRelay?.peer_id === "string" ? offeredRelay.peer_id : null;
|
|
124
|
+
const relayAddrs = Array.isArray(offeredRelay?.multiaddrs)
|
|
125
|
+
? offeredRelay.multiaddrs.filter((a) => typeof a === "string")
|
|
126
|
+
: [];
|
|
127
|
+
if (relayPeerId && relayAddrs.length > 0) {
|
|
128
|
+
const base = relayAddrs[0];
|
|
129
|
+
// The circuit address form the walk uses: the relay's own address with `/p2p-circuit`.
|
|
130
|
+
const circuitAddr = base.includes(`/p2p/${relayPeerId}`)
|
|
131
|
+
? `${base}/p2p-circuit`
|
|
132
|
+
: `${base}/p2p/${relayPeerId}/p2p-circuit`;
|
|
133
|
+
const took = await deps.reserveOnDemand(circuitAddr, Buffer.from(sessionId).toString("hex"));
|
|
134
|
+
deps.logger.info("session.offer.reservation", {
|
|
135
|
+
agentName: deps.agentName,
|
|
136
|
+
relayPeerId,
|
|
137
|
+
granted: took,
|
|
138
|
+
impact: took
|
|
139
|
+
? "this agent is dialable through the relay the directory named, for the life of this session"
|
|
140
|
+
: "no reservation on the offered relay — a counterparty behind NAT cannot dial this " +
|
|
141
|
+
"agent for this session, and it will be reached over the relay's store-and-forward",
|
|
142
|
+
});
|
|
143
|
+
// Re-read: the endpoint we advertise has to include the circuit we just took.
|
|
144
|
+
sr = deps.getStandingReceiverEndpoint() ?? sr;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
/**
|
|
148
|
+
* ⚠️ **AN OFFER THAT NAMES NO RELAY USED TO ASK NOBODY AND SAY NOTHING — 056-SLOTDEAD, F8.**
|
|
149
|
+
*
|
|
150
|
+
* `session.offer.reservation` only fires when a relay WAS named, so this branch was silent.
|
|
151
|
+
* The failure that makes silence expensive: if the directory stops naming a relay — an old
|
|
152
|
+
* node in the pool, a bad roll, a regression in `pickRelay` — a relay-only agent refuses
|
|
153
|
+
* every inbound call with `relay_only_no_reservation`. That reason reads as "no relay would
|
|
154
|
+
* grant me a slot", so the operator goes and looks at relay capacity, and the fault is on
|
|
155
|
+
* the directory and has nothing to do with slots. One line makes that a grep.
|
|
156
|
+
*
|
|
157
|
+
* INFO, not WARN: against a directory that has not rolled yet this is the expected shape,
|
|
158
|
+
* and the agent degrades correctly to its direct address. It is loud enough to find, and it
|
|
159
|
+
* says which of the two states it is.
|
|
160
|
+
*/
|
|
161
|
+
deps.logger.info("session.offer.reservation.not_offered", {
|
|
162
|
+
agentName: deps.agentName,
|
|
163
|
+
hasRelayEndpoint: offeredRelay !== undefined,
|
|
164
|
+
impact: offeredRelay === undefined
|
|
165
|
+
? "the directory's offer named no relay, so this agent asked nobody for a slot and will " +
|
|
166
|
+
"answer with the addresses it already has. Expected against a directory that predates " +
|
|
167
|
+
"on-demand reservations; unexpected otherwise, and under relay-only it means the call " +
|
|
168
|
+
"is about to be refused for a reason that points at the wrong side."
|
|
169
|
+
: "the offer carried a relay_endpoint this agent could not read — no usable peer id or " +
|
|
170
|
+
"no multiaddrs — so no slot was asked for. That is a malformed frame from the " +
|
|
171
|
+
"directory, not a relay at capacity.",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// DOD-M15-RELAYONLY-1: ANSWER, never publish an empty address list — **but only when
|
|
175
|
+
// relay-only is what emptied it.**
|
|
176
|
+
//
|
|
177
|
+
// ⚠️ An empty `addrs` is NOT exclusively a relay-only condition, and the first version of this
|
|
178
|
+
// guard refused unconditionally — which broke the pre-existing accept path for a receiver that
|
|
179
|
+
// legitimately has no addresses yet, a case `session-ceremony-verify` covers on purpose. A
|
|
180
|
+
// privacy control that changes behaviour when it is switched OFF is its own defect.
|
|
181
|
+
//
|
|
182
|
+
// ⚠️ Under relay-only the endpoint is already filtered to circuit addresses, and with no relay
|
|
183
|
+
// reservation that set is EMPTY. The directory folds an accept only
|
|
184
|
+
// `if (counterparty_session_addrs.length > 0)` — **with no `else`** — so an empty accept is
|
|
185
|
+
// dropped in silence, the offer waiter never resolves, and the INITIATOR's operator is told
|
|
186
|
+
// `counterparty_unavailable`: a lie about our state, produced by our setting. Rejecting
|
|
187
|
+
// explicitly keeps the failure attributable to the side that caused it, and is the same
|
|
188
|
+
// answer-never-vanish contract the reject path above already implements.
|
|
189
|
+
/**
|
|
190
|
+
* ⚠️ **AFTER THE ON-DEMAND RESERVE, NOT BEFORE IT — 055-ONDEMAND.** An idle agent holds no
|
|
191
|
+
* reservation by design now, so this guard sitting above the reserve would fire on EVERY
|
|
192
|
+
* inbound offer and take `DOD-M15-RELAYONLY-1` — the control that stops a session revealing
|
|
193
|
+
* the operator's IP — to a 100% refusal rate. Down here it means what it has always meant:
|
|
194
|
+
* relay-only is on and we could not get a circuit, so there is nothing we are willing to
|
|
195
|
+
* advertise.
|
|
196
|
+
*/
|
|
197
|
+
if (sr.addrs.length === 0 && (deps.isRelayOnly?.() ?? false)) {
|
|
198
|
+
deps.logger.warn("session.offer.abort", {
|
|
199
|
+
agentName: deps.agentName,
|
|
200
|
+
reason: "relay_only_no_reservation",
|
|
201
|
+
impact: "relay-only is on and this agent holds no relay reservation, so it has no circuit " +
|
|
202
|
+
"address to advertise and will not reveal its own — the offer is refused rather than " +
|
|
203
|
+
"answered with an empty endpoint the directory would silently drop",
|
|
204
|
+
});
|
|
205
|
+
await sendOfferReject(sessionId, "relay_only_no_reservation");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* DOD-M15-ASSIGN-1 — open the door to the named dialer, and ONLY then publish our address.
|
|
210
|
+
*
|
|
211
|
+
* The ordering is the whole mechanism. Our receiver admits nobody until this line runs; the
|
|
212
|
+
* accept below is what tells the directory (and through it, the initiator) where we listen.
|
|
213
|
+
* Narrowing first means the gate names the initiator before the initiator can possibly know
|
|
214
|
+
* where to dial, so there is no interval in which the address is reachable by anyone else.
|
|
215
|
+
*
|
|
216
|
+
* REFUSED WHEN THE OFFER NAMES NOBODY. The directory rejects any session_request that omits
|
|
217
|
+
* `initiator_session_peer_id` (`session_request_missing_peer_id`), so a well-formed request
|
|
218
|
+
* cannot produce a nameless offer — one here means a directory that is broken or lying.
|
|
219
|
+
* Advertising anyway would be the worse failure: the initiator would dial an address whose
|
|
220
|
+
* gate refuses them, and the session would die at the transport with no one able to say why.
|
|
221
|
+
* Rejecting names the cause on the frame the directory is already waiting for.
|
|
222
|
+
*/
|
|
223
|
+
const offeredDialerRaw = frame["initiator_session_peer_id"];
|
|
224
|
+
const offeredDialer = typeof offeredDialerRaw === "string" ? offeredDialerRaw : "";
|
|
225
|
+
// Keyed by SESSION (review F1): two overlapping offers to one agent must not overwrite
|
|
226
|
+
// each other's record, or a legitimate session is refused and the check disarms itself.
|
|
227
|
+
const narrowed = deps.admitOfferedDialer(offeredDialer, Buffer.from(sessionId).toString("hex"));
|
|
228
|
+
if (narrowed !== "narrowed") {
|
|
229
|
+
/**
|
|
230
|
+
* Review F6 — ONE REASON PER CAUSE. This branch used to report `offer_named_no_dialer` for
|
|
231
|
+
* both outcomes, and its guidance sent the operator to "the directory is not populating
|
|
232
|
+
* initiator_session_peer_id" even when the truth was that this agent had no standing
|
|
233
|
+
* receiver. That is a local problem wearing a remote label, which is the exact shape that
|
|
234
|
+
* costs days. `standing_receiver_unavailable` already exists two branches above and is the
|
|
235
|
+
* correct name for it.
|
|
236
|
+
*/
|
|
237
|
+
const isLocal = narrowed === "no_receiver";
|
|
238
|
+
const reason = isLocal ? "standing_receiver_unavailable" : "offer_named_no_dialer";
|
|
239
|
+
deps.logger.warn("session.offer.abort", {
|
|
240
|
+
agentName: deps.agentName,
|
|
241
|
+
reason,
|
|
242
|
+
impact: isLocal
|
|
243
|
+
? "this agent has no standing receiver to open, so it cannot serve the session; the session was refused rather than accepted with nowhere to be dialled"
|
|
244
|
+
: "the directory's offer did not say who would dial, so this agent could not open its receiver to exactly one peer; the session was refused rather than served behind a door open to anyone",
|
|
245
|
+
guidance: isLocal
|
|
246
|
+
? "the receiver is created when the agent comes online — check that cello_start_agent reached this daemon, then have the initiator retry"
|
|
247
|
+
: "the initiator should retry; a repeat means the directory is not populating initiator_session_peer_id and the session cannot be established safely",
|
|
248
|
+
});
|
|
249
|
+
await sendOfferReject(sessionId, reason);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
// Same production contract as the reject above (D1 review F3, pre-existing): sendRaw
|
|
254
|
+
// resolves {ok:false, reason} instead of throwing. Logging "accepted" on {ok:false}
|
|
255
|
+
// pointed the operator away from the exact failure that fabricates phantom sessions —
|
|
256
|
+
// the directory hears nothing, stalls 2 s, and signs an endpoint-less assignment.
|
|
257
|
+
const res = await deps.signaling.sendRaw({
|
|
258
|
+
type: "session_offer_accept",
|
|
259
|
+
session_id: sessionId,
|
|
260
|
+
counterparty_session_peer_id: sr.peerId,
|
|
261
|
+
counterparty_session_addrs: sr.addrs,
|
|
262
|
+
});
|
|
263
|
+
if (res.ok) {
|
|
264
|
+
deps.logger.info("session.offer.accepted", {
|
|
265
|
+
agentName: deps.agentName,
|
|
266
|
+
sessionPeerId: sr.peerId,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
deps.logger.warn("session.offer.accept.failed", {
|
|
271
|
+
agentName: deps.agentName,
|
|
272
|
+
detail: res.reason ?? "send_not_ok",
|
|
273
|
+
...(res.guidance ? { guidance: res.guidance } : {}),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
deps.logger.warn("session.offer.accept.failed", {
|
|
279
|
+
agentName: deps.agentName,
|
|
280
|
+
detail: extractErrorMessage(err),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
})();
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Reconstruct the agent's FROST threshold signer from its persisted share, configured to
|
|
288
|
+
* drive the ceremony's `/cello/frost/1.0.0` round-trips on the agent's directory node.
|
|
289
|
+
* Returns null when no share is persisted or the share is unreadable.
|
|
290
|
+
*/
|
|
291
|
+
async function hydrateShareAndStubs(deps) {
|
|
292
|
+
const share = await deps.persistence.loadActiveFrostKeyShare();
|
|
293
|
+
if (!share)
|
|
294
|
+
return null;
|
|
295
|
+
const frostSecret = { identifier: share.identifier, signingShare: new Uint8Array(share.signingShare) };
|
|
296
|
+
let commitments = [];
|
|
297
|
+
const verifyingShares = {};
|
|
298
|
+
try {
|
|
299
|
+
const dc = decode(Buffer.from(share.commitmentsCbor));
|
|
300
|
+
if (Array.isArray(dc)) {
|
|
301
|
+
commitments = dc.map((c) => c instanceof Uint8Array ? c : Buffer.isBuffer(c) ? new Uint8Array(c) : new Uint8Array(0));
|
|
302
|
+
}
|
|
303
|
+
const dvs = decode(Buffer.from(share.verifyingSharesCbor));
|
|
304
|
+
if (dvs && typeof dvs === "object" && !Array.isArray(dvs)) {
|
|
305
|
+
for (const [k, v] of Object.entries(dvs)) {
|
|
306
|
+
verifyingShares[k] = v instanceof Uint8Array ? v : Buffer.isBuffer(v) ? new Uint8Array(v) : new Uint8Array(0);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
deps.logger.error("session.ceremony.share.load.failed", {
|
|
312
|
+
agentName: deps.agentName,
|
|
313
|
+
reason: "cbor_deserialize_failed",
|
|
314
|
+
detail: extractErrorMessage(err),
|
|
315
|
+
});
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
const frostPublic = { signers: { min: share.threshold, max: share.participants + 1 }, commitments, verifyingShares };
|
|
319
|
+
try {
|
|
320
|
+
// SI-001: storeDkgResult does not log the secret. Cast via the function's own param
|
|
321
|
+
// types (the daemon has no direct @noble/curves dependency).
|
|
322
|
+
storeDkgResult(deps.agentPubkeyHex, frostSecret, frostPublic);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
deps.logger.error("session.ceremony.share.load.failed", {
|
|
326
|
+
agentName: deps.agentName,
|
|
327
|
+
reason: "storeDkgResult_failed",
|
|
328
|
+
detail: extractErrorMessage(err),
|
|
329
|
+
});
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
// DOD-SIGN-1: build a directory-node stub PER consortium node so the FROST threshold signer
|
|
333
|
+
// can run the signing ceremony across ALL N nodes (it reaches any T and excludes a node that's
|
|
334
|
+
// down — "kill a node, still signs"). With no consortium manifest configured the roster is null
|
|
335
|
+
// → the single primary endpoint (M6/M7 single-node back-compat). NOTE: the share's threshold T
|
|
336
|
+
// (from the multi-node DKG) is FIXED — a degraded roster (fewer than T reachable) makes signing
|
|
337
|
+
// FAIL, it can never forge a lower-threshold signature, so a single-stub fallback is safe.
|
|
338
|
+
let directoryNodeStubs;
|
|
339
|
+
const node = deps.getNode();
|
|
340
|
+
const roster = await deps.getConsortiumEndpoints();
|
|
341
|
+
// Use the share's CURRENT epoch (advances after a proactive refresh) — NOT a hardcoded epoch:1, else
|
|
342
|
+
// post-refresh signing would target the now-EXPIRED epoch and fail (DOD-REFRESH-1). For an un-refreshed
|
|
343
|
+
// agent share.epochId IS "…:epoch:1", so this is identical to the prior behavior.
|
|
344
|
+
const epochId = share.epochId;
|
|
345
|
+
// The stub's FROST identifier (`id`) MUST be the node's DKG label, NOT its libp2p peerId. The directory
|
|
346
|
+
// derives each node's FROST participant identifier as derive(nodeId), where nodeId = the node's region
|
|
347
|
+
// (frost-handler.ts:23 `nodeIdentifier = derive(nodeId)`; the bin sets nodeId = region). So the group's
|
|
348
|
+
// node shares are bound to derive(region), and the node SIGNS under derive(region). If the client verifies
|
|
349
|
+
// /aggregates partials under derive(peerId) instead, every verifyShare fails → all nodes excluded →
|
|
350
|
+
// ceremony_exhausted. `id` feeds Identifier.derive() in the signer; `directoryPeerId` is the network dial
|
|
351
|
+
// and stays the libp2p peerId. (nodeId and peerId coincide only for legacy single-node agents whose DKG
|
|
352
|
+
// predates the region-as-nodeId change — the single-node fallback below passes peerId for that reason.)
|
|
353
|
+
const mkStub = (nodeId, peerId, multiaddr) => {
|
|
354
|
+
const stub = new NetworkDirectoryNode({
|
|
355
|
+
id: nodeId,
|
|
356
|
+
node: node,
|
|
357
|
+
directoryPeerId: peerId,
|
|
358
|
+
directoryMultiaddrs: [multiaddr],
|
|
359
|
+
logger: deps.logger,
|
|
360
|
+
});
|
|
361
|
+
stub.setBootstrapContext(deps.agentPubkeyHex, epochId, (h) => deps.keyProvider.sign(h)); // SEC-2
|
|
362
|
+
return stub;
|
|
363
|
+
};
|
|
364
|
+
if (node && roster !== null && roster.length > 0) {
|
|
365
|
+
// M8B quorum: filter the live roster to the SHARE-HOLDER quorum Q the agent registered with
|
|
366
|
+
// (share.directoryNodeIds), so the seal targets holders — not nodes that came back online after a
|
|
367
|
+
// quorum registration but hold NO share for this agent (they'd pad the count via isReachable()===true
|
|
368
|
+
// and burn the retry budget). Absent Q (pre-quorum agent / single-node) → full roster (unchanged
|
|
369
|
+
// DOD-SIGN-1). Defensive: if every Q node has vanished from the roster, fall back to the full roster
|
|
370
|
+
// rather than an empty signer set (the ceremony's own below-threshold pre-check then applies).
|
|
371
|
+
const q = share.directoryNodeIds;
|
|
372
|
+
const filtered = q && q.length > 0 ? roster.filter((ep) => q.includes(ep.nodeId)) : roster;
|
|
373
|
+
const holders = filtered.length > 0 ? filtered : roster;
|
|
374
|
+
// FROST id = ep.nodeId (region — the DKG label); network dial = ep.peerId.
|
|
375
|
+
directoryNodeStubs = holders.map((ep) => mkStub(ep.nodeId, ep.peerId, ep.multiaddr));
|
|
376
|
+
}
|
|
377
|
+
else if (node) {
|
|
378
|
+
// No consortium manifest (roster null) or a configured manifest that resolved EMPTY → the single
|
|
379
|
+
// primary endpoint. INTENTIONAL asymmetry with DKG-1 (which REFUSES a configured-but-empty roster
|
|
380
|
+
// because DKG needs all N): for SIGNING the share's threshold T is FIXED, so a degraded/single
|
|
381
|
+
// stub makes participateInCeremony fail the `reachable < T-1` pre-check rather than forge a weaker
|
|
382
|
+
// seal — safe. WARN distinctly on the configured-but-unreachable case so the operator sees "your
|
|
383
|
+
// consortium was unreachable" rather than a generic below-threshold error (fallback-finder F3).
|
|
384
|
+
if (roster !== null && roster.length === 0) {
|
|
385
|
+
deps.logger.warn("session.ceremony.consortium_unreachable", { agentName: deps.agentName });
|
|
386
|
+
}
|
|
387
|
+
const ep = await deps.getDirectoryEndpoint();
|
|
388
|
+
if (ep && ep.multiaddr) {
|
|
389
|
+
// Single-node back-compat: no region is available from getDirectoryEndpoint, and legacy single-node
|
|
390
|
+
// agents' DKG labeled the node by peerId (pre region-as-nodeId), so the FROST id stays the peerId here.
|
|
391
|
+
directoryNodeStubs = [mkStub(ep.peerId, ep.peerId, ep.multiaddr)];
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return { share, stubs: directoryNodeStubs };
|
|
395
|
+
}
|
|
396
|
+
export async function reconstructThresholdSigner(deps,
|
|
397
|
+
/**
|
|
398
|
+
* DOD-M15-SEALPARTIES-1: the signed leaves this ceremony's TBS is a root over, forwarded to every
|
|
399
|
+
* directory node so each reaches its own verdict instead of signing a claim. Supplied on the seal
|
|
400
|
+
* ceremony and on nothing else — a co-signer requires it under the seal context and ignores it
|
|
401
|
+
* everywhere else.
|
|
402
|
+
*/
|
|
403
|
+
sealEvidence) {
|
|
404
|
+
const h = await hydrateShareAndStubs(deps);
|
|
405
|
+
if (!h)
|
|
406
|
+
return null;
|
|
407
|
+
if (sealEvidence)
|
|
408
|
+
for (const stub of h.stubs ?? [])
|
|
409
|
+
stub.setSealEvidence(sealEvidence);
|
|
410
|
+
return new FrostThresholdSigner({ threshold: h.share.threshold, participants: h.share.participants, directoryNodeStubs: h.stubs }, Buffer.from(deps.agentPubkeyHex, "hex"));
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* M8B DOD-REFRESH-1: run a proactive share refresh for an already-registered agent. Rotates the client's
|
|
414
|
+
* + every directory node's share to the next epoch (group public key unchanged), then persists the
|
|
415
|
+
* client's new share as the active one so subsequent signing uses the new epoch and old-epoch shares die.
|
|
416
|
+
*/
|
|
417
|
+
export async function runAgentRefresh(deps) {
|
|
418
|
+
const h = await hydrateShareAndStubs(deps);
|
|
419
|
+
if (!h)
|
|
420
|
+
return { ok: false, reason: "no_active_share" };
|
|
421
|
+
if (!h.stubs || h.stubs.length === 0)
|
|
422
|
+
return { ok: false, reason: "no_directory_nodes" };
|
|
423
|
+
const fromEpochN = Number(/:epoch:(\d+)$/.exec(h.share.epochId)?.[1] ?? "1");
|
|
424
|
+
let result;
|
|
425
|
+
try {
|
|
426
|
+
result = await runNetworkRefresh(Buffer.from(deps.agentPubkeyHex, "hex"), {
|
|
427
|
+
threshold: h.share.threshold,
|
|
428
|
+
participants: h.share.participants,
|
|
429
|
+
directoryNodes: h.stubs,
|
|
430
|
+
fromEpochN,
|
|
431
|
+
signAuth: (hash) => deps.keyProvider.sign(hash), // SEC-2
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
deps.logger.error("refresh.ceremony.failed", {
|
|
436
|
+
agentName: deps.agentName,
|
|
437
|
+
detail: extractErrorMessage(err),
|
|
438
|
+
});
|
|
439
|
+
return { ok: false, reason: "ceremony_failed" };
|
|
440
|
+
}
|
|
441
|
+
const primaryPubkeyHex = Buffer.from(result.primaryPubkey).toString("hex");
|
|
442
|
+
// M2 (defense-in-depth): the group public key MUST be byte-identical to the PRE-refresh key. The
|
|
443
|
+
// cross-node check inside runNetworkRefresh only proves all parties AGREE post-refresh — a uniform
|
|
444
|
+
// secret-shift (a crypto-core regression) would move the key on every party identically and pass it,
|
|
445
|
+
// while silently diverging from the registered key counterparties verify seals against. Assert against
|
|
446
|
+
// the KNOWN pre-refresh key (h.share.primaryPubkey) and abort WITHOUT persisting on mismatch.
|
|
447
|
+
if (primaryPubkeyHex !== h.share.primaryPubkey) {
|
|
448
|
+
deps.logger.error("refresh.ceremony.group_key_changed", {
|
|
449
|
+
agentName: deps.agentName,
|
|
450
|
+
expected: h.share.primaryPubkey.slice(0, 16),
|
|
451
|
+
got: primaryPubkeyHex.slice(0, 16),
|
|
452
|
+
});
|
|
453
|
+
return { ok: false, reason: "group_key_changed" };
|
|
454
|
+
}
|
|
455
|
+
// verifyingShares are PUBLIC (s_j·G per participant) and MOVE on a real refresh while commitments[0]
|
|
456
|
+
// (the group key) does not — so their digest is the one observable that distinguishes a genuine
|
|
457
|
+
// rotation from a no-op "relabel" (the spine asserts it changes across two refreshes). SI-001-safe.
|
|
458
|
+
const verifyingSharesDigest = createHash("sha256")
|
|
459
|
+
.update(Object.keys(result.verifyingShares)
|
|
460
|
+
.sort()
|
|
461
|
+
.map((k) => `${k}:${Buffer.from(result.verifyingShares[k]).toString("hex")}`)
|
|
462
|
+
.join("|"))
|
|
463
|
+
.digest("hex");
|
|
464
|
+
// L7: a persist failure here is the most dangerous point (directories already advanced) — surface it
|
|
465
|
+
// as a STRUCTURED reason rather than letting a raw throw escape the handler.
|
|
466
|
+
try {
|
|
467
|
+
await deps.persistence.persistFrostKeyShare({
|
|
468
|
+
epochId: `${deps.agentPubkeyHex}:epoch:${result.toEpochN}`,
|
|
469
|
+
primaryPubkey: primaryPubkeyHex,
|
|
470
|
+
identifier: result.identifier,
|
|
471
|
+
signingShare: result.signingShare,
|
|
472
|
+
threshold: h.share.threshold,
|
|
473
|
+
participants: h.share.participants,
|
|
474
|
+
commitmentsCbor: encodeCbor(result.commitments),
|
|
475
|
+
verifyingSharesCbor: encodeCbor(result.verifyingShares),
|
|
476
|
+
dkgMethod: "network_dkg",
|
|
477
|
+
// M8B quorum: a proactive refresh re-randomizes shares among the SAME membership — carry the
|
|
478
|
+
// quorum Q forward, else this UPDATE wipes frost_directory_node_ids to NULL and the next restart's
|
|
479
|
+
// seal falls back to the full roster (reintroducing the padding/retry-budget bug the persist fixed).
|
|
480
|
+
directoryNodeIds: h.share.directoryNodeIds,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
catch (err) {
|
|
484
|
+
deps.logger.error("refresh.ceremony.persist_failed", {
|
|
485
|
+
agentName: deps.agentName,
|
|
486
|
+
detail: extractErrorMessage(err),
|
|
487
|
+
});
|
|
488
|
+
return { ok: false, reason: "persist_failed" };
|
|
489
|
+
}
|
|
490
|
+
deps.logger.info("refresh.ceremony.complete", {
|
|
491
|
+
agentName: deps.agentName,
|
|
492
|
+
toEpoch: result.toEpochN,
|
|
493
|
+
primaryPubkey: primaryPubkeyHex.slice(0, 16),
|
|
494
|
+
});
|
|
495
|
+
return { ok: true, toEpochN: result.toEpochN, primaryPubkey: primaryPubkeyHex, verifyingSharesDigest };
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Register a `ceremony_request` handler on the agent's signaling seam. On the directory's
|
|
499
|
+
* delegated-signing request, run the agent's threshold signer's participateInCeremony and
|
|
500
|
+
* reply with `ceremony_result`. The signer is reconstructed lazily and cached. Returns the
|
|
501
|
+
* unregister function. SI-001: tbs/signature never logged.
|
|
502
|
+
*/
|
|
503
|
+
/**
|
|
504
|
+
* DOD-SPINE-7: register a `seal_verified` handler on the agent's signaling seam. After the
|
|
505
|
+
* directory rebuilds + verifies the bilateral seal's signed Merkle chain (relay-mediated
|
|
506
|
+
* processSeal FROST path), it sends the SEAL INITIATOR a `seal_verified` {session_id,
|
|
507
|
+
* sealed_root, leaf_count, timestamp} and waits for the initiator to COORDINATE the seal FROST
|
|
508
|
+
* ceremony. This handler reconstructs the agent's threshold signer (same machinery as the
|
|
509
|
+
* session ceremony), runs participateInCeremony over buildSealTbs with context
|
|
510
|
+
* "cello-frost-seal-v1", and replies `seal_frost_signature` {session_id, frost_signature}. The
|
|
511
|
+
* directory's #processSealFrostSignature then completes notarization and delivers
|
|
512
|
+
* `session_sealed` (the byte-identical sealed_root) to both parties.
|
|
513
|
+
*
|
|
514
|
+
* SI-001: tbs/signature never logged.
|
|
515
|
+
*/
|
|
516
|
+
export function wireSealCeremonyHandler(deps) {
|
|
517
|
+
return deps.signaling.registerInboundHandler((frame) => {
|
|
518
|
+
if (frame["type"] !== "seal_verified")
|
|
519
|
+
return;
|
|
520
|
+
void (async () => {
|
|
521
|
+
const toU8 = (v) => v instanceof Uint8Array ? v : Buffer.isBuffer(v) ? new Uint8Array(v) : null;
|
|
522
|
+
const sessionId = toU8(frame["session_id"]);
|
|
523
|
+
const sealedRoot = toU8(frame["sealed_root"]);
|
|
524
|
+
const leafCountRaw = frame["leaf_count"];
|
|
525
|
+
const leafCount = typeof leafCountRaw === "number" ? leafCountRaw : null;
|
|
526
|
+
const tsRaw = frame["timestamp"];
|
|
527
|
+
const timestamp = typeof tsRaw === "number" ? tsRaw : typeof tsRaw === "bigint" ? Number(tsRaw) : null;
|
|
528
|
+
if (!sessionId || !sealedRoot || leafCount === null || timestamp === null) {
|
|
529
|
+
deps.logger.warn("session.seal.ceremony.abort", {
|
|
530
|
+
agentName: deps.agentName,
|
|
531
|
+
reason: !sessionId ? "no_session_id" : !sealedRoot ? "no_sealed_root" : leafCount === null ? "no_leaf_count" : "no_timestamp",
|
|
532
|
+
});
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const sidHex = Buffer.from(sessionId).toString("hex");
|
|
536
|
+
/**
|
|
537
|
+
* DOD-M15-SEALPARTIES-1: forward the raw signed leaves to every co-signing directory.
|
|
538
|
+
*
|
|
539
|
+
* They arrive on `seal_verified` and are already re-verified on this side (the frontier
|
|
540
|
+
* re-derivation below reads the same array). Forwarding them is what lets a node that did NOT
|
|
541
|
+
* run the verification rebuild the root itself and refuse a certificate over a leaf set the
|
|
542
|
+
* participants never produced — the difference between three signatures that mean three
|
|
543
|
+
* independent judgements and three that rest on one node's reading.
|
|
544
|
+
*
|
|
545
|
+
* Absent here means the frame carried none, and the directories refuse on that: it is not
|
|
546
|
+
* this side's place to decide the evidence was optional.
|
|
547
|
+
*/
|
|
548
|
+
const sealEvidenceLeaves = Array.isArray(frame["frontier_leaves"]) && frame["frontier_leaves"].length > 0
|
|
549
|
+
? frame["frontier_leaves"]
|
|
550
|
+
: undefined;
|
|
551
|
+
// Reconstruct a FRESH signer per ceremony (same rationale as the session ceremony:
|
|
552
|
+
// fresh directory endpoint, no shared FROST state across concurrent ceremonies).
|
|
553
|
+
/**
|
|
554
|
+
* ⚠️ ABSENT IS PASSED AS ABSENT — fallback hunt, finding 4. This used to send `[]`, which the
|
|
555
|
+
* co-signer classified as MALFORMED ("compare builds") rather than MISSING ("someone is asking
|
|
556
|
+
* for a signature without showing the record"). The seal failed either way; the diagnosis the
|
|
557
|
+
* module exists to produce was the one case it could never reach.
|
|
558
|
+
*/
|
|
559
|
+
/**
|
|
560
|
+
* Review F6: what each holder SAID, kept so the recorded failure can name it. "Threshold not
|
|
561
|
+
* met" is a count; `SEAL_ROOT_UNSUPPORTED` from a holder is an accusation against the
|
|
562
|
+
* verifying directory, and the operator surface should be able to tell them apart.
|
|
563
|
+
*/
|
|
564
|
+
const cosignRefusals = new Set();
|
|
565
|
+
const signer = await reconstructThresholdSigner(deps, sealEvidenceLeaves
|
|
566
|
+
? { leaves: sealEvidenceLeaves, closeTimestamp: timestamp, onRefused: (r) => cosignRefusals.add(r) }
|
|
567
|
+
: undefined);
|
|
568
|
+
if (!signer) {
|
|
569
|
+
deps.logger.warn("session.seal.ceremony.abort", { agentName: deps.agentName, sessionId: sidHex, reason: "no_signer" });
|
|
570
|
+
deps.recordSealFailure(deps.agentName, sidHex, "seal_ceremony_no_signer", "unresolved");
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
// M7 legibility-TBS-binding: when the directory's seal_verified carries `legibility` (the
|
|
574
|
+
// bilateral seal), fold its canonical hash into the TBS we co-sign — so the FROST signature
|
|
575
|
+
// covers the legibility and a MITM cannot tamper answered/frontier/attestation_mode in
|
|
576
|
+
// transit. The directory binds the IDENTICAL hash (it built the TBS it verifies against);
|
|
577
|
+
// the receiving client re-binds and verifies. Unilateral seal_verified carries no legibility
|
|
578
|
+
// → plain TBS (bindLegibilityToTbs is a no-op), matching the directory's unilateral TBS.
|
|
579
|
+
const legibility = frame["legibility"];
|
|
580
|
+
const legForHash = legibility && typeof legibility === "object" ? legibility : null;
|
|
581
|
+
// DOD-LEG-2 (SI-002): the INITIATOR must not co-sign an inflated certificate — otherwise a
|
|
582
|
+
// validly-FROST-signed inflated cert would exist as a durable artifact. Re-derive each party's
|
|
583
|
+
// content_frontier_seq from the signed leaves the directory ships on seal_verified and ABORT
|
|
584
|
+
// the ceremony (no signature) if any published frontier is inflated. Same logic the receiver
|
|
585
|
+
// applies at session_sealed; doing it here means a lying directory gets NO signature at all.
|
|
586
|
+
const wireParts = legForHash && Array.isArray(legForHash.participants)
|
|
587
|
+
? (legForHash.participants)
|
|
588
|
+
: null;
|
|
589
|
+
if (wireParts) {
|
|
590
|
+
// Wire pubkeys are Uint8Array; normalise to hex for comparison with the re-derived map.
|
|
591
|
+
const parts = wireParts.map((p) => ({
|
|
592
|
+
pubkey: p.pubkey instanceof Uint8Array
|
|
593
|
+
? Buffer.from(p.pubkey).toString("hex")
|
|
594
|
+
: (typeof p.pubkey === "string" ? p.pubkey : null),
|
|
595
|
+
content_frontier_seq: typeof p.content_frontier_seq === "number" ? p.content_frontier_seq : null,
|
|
596
|
+
}));
|
|
597
|
+
const malformed = parts.some((p) => p.pubkey === null || p.content_frontier_seq === null);
|
|
598
|
+
const anyClaimed = parts.some((p) => (p.content_frontier_seq ?? 0) > 0);
|
|
599
|
+
const flRaw = frame["frontier_leaves"];
|
|
600
|
+
const haveLeaves = Array.isArray(flRaw) && flRaw.length > 0;
|
|
601
|
+
if (malformed || (anyClaimed && !haveLeaves)) {
|
|
602
|
+
const abortReason = malformed ? "frontier_participant_malformed" : "frontier_leaves_missing";
|
|
603
|
+
deps.logger.warn("session.seal.ceremony.abort", {
|
|
604
|
+
agentName: deps.agentName, sessionId: sidHex, reason: abortReason,
|
|
605
|
+
});
|
|
606
|
+
deps.recordSealFailure(deps.agentName, sidHex, abortReason, "unresolved");
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
if (haveLeaves) {
|
|
610
|
+
const toLeaf = (v) => (v instanceof Uint8Array ? v : new Uint8Array(v));
|
|
611
|
+
const leaves = flRaw.map((l) => {
|
|
612
|
+
const o = l;
|
|
613
|
+
return { structure1_cbor: toLeaf(o["structure1_cbor"]), sender_pubkey: toLeaf(o["sender_pubkey"]), sender_signature: toLeaf(o["sender_signature"]) };
|
|
614
|
+
});
|
|
615
|
+
const rederived = reDeriveFrontiers(leaves, sessionId);
|
|
616
|
+
const inflated = rederived.ok
|
|
617
|
+
? findInflatedFrontier(parts, rederived.frontiers)
|
|
618
|
+
: null;
|
|
619
|
+
if (!rederived.ok || inflated) {
|
|
620
|
+
const inflatedReason = rederived.ok ? "frontier_unverifiable" : rederived.reason;
|
|
621
|
+
deps.logger.warn("session.seal.ceremony.abort", {
|
|
622
|
+
agentName: deps.agentName, sessionId: sidHex,
|
|
623
|
+
reason: inflatedReason,
|
|
624
|
+
...(inflated ? { party: inflated.party, publishedFrontier: inflated.publishedFrontier, derivedFrontier: inflated.derivedFrontier } : {}),
|
|
625
|
+
});
|
|
626
|
+
deps.recordSealFailure(deps.agentName, sidHex, inflatedReason, "unresolved");
|
|
627
|
+
return; // refuse to co-sign — the directory gets no signature for an inflated cert
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* DO NOT SIGN A ROOT THIS AGENT HAS NOT CHECKED — bullet 2's co-signing half (review F1).
|
|
633
|
+
*
|
|
634
|
+
* Same predicate as the receiving path, deliberately: one implementation, so the two halves
|
|
635
|
+
* cannot drift into disagreeing about what counts as a mismatch.
|
|
636
|
+
*
|
|
637
|
+
* `cannot_judge` REFUSES here, where the accept path tolerates it — and the asymmetry is the
|
|
638
|
+
* point. Accepting an unverifiable certificate keeps a receipt that already exists; SIGNING an
|
|
639
|
+
* unverifiable one manufactures a new, durable, non-repudiable claim with this agent's key on
|
|
640
|
+
* it. The safe default is opposite in each direction: tolerate on the way in, refuse on the way
|
|
641
|
+
* out.
|
|
642
|
+
*/
|
|
643
|
+
// The evidence travels too: a side that restarted mid-session can never receive the counterparty's
|
|
644
|
+
// SEAL leaf, but the request it is being asked to sign already carries it, signed.
|
|
645
|
+
const rootCheck = deps.verifyCertifiedRoot(deps.agentPubkeyHex, sidHex, sealedRoot, leafCount, sealEvidenceLeaves);
|
|
646
|
+
if (rootCheck.verdict !== "match") {
|
|
647
|
+
deps.logger.error("session.seal.ceremony.abort", {
|
|
648
|
+
agentName: deps.agentName, sessionId: sidHex,
|
|
649
|
+
reason: rootCheck.verdict === "mismatch" ? "root_mismatch" : "root_unverifiable",
|
|
650
|
+
detail: rootCheck.verdict === "mismatch" ? rootCheck.detail : rootCheck.reason,
|
|
651
|
+
...(rootCheck.verdict === "mismatch" && rootCheck.ownRootHex ? { ownRoot: rootCheck.ownRootHex } : {}),
|
|
652
|
+
impact: "this agent REFUSED to co-sign. Signing would have put its key on a notarization it " +
|
|
653
|
+
"cannot confirm describes this conversation — a durable, valid, non-repudiable claim " +
|
|
654
|
+
"about a transcript it never checked. The session is not sealed; nothing is lost.",
|
|
655
|
+
guidance: "Compare the leaf count with the counterparty and check the directory and relay logs for " +
|
|
656
|
+
"this session id. Do NOT force-abandon: that forfeits the receipt permanently.",
|
|
657
|
+
});
|
|
658
|
+
deps.recordSealFailure(deps.agentName, sidHex, rootCheck.verdict === "mismatch" ? "seal_root_mismatch" : "seal_root_unverifiable", "unresolved");
|
|
659
|
+
return; // refuse to co-sign — the directory gets no signature for a root we cannot verify
|
|
660
|
+
}
|
|
661
|
+
const tbs = bindLegibilityToTbs(buildSealTbs(sessionId, sealedRoot, leafCount, timestamp), legForHash);
|
|
662
|
+
let frostSignature = null;
|
|
663
|
+
try {
|
|
664
|
+
// The initiator COORDINATES the seal FROST ceremony (its signer drives the
|
|
665
|
+
// /cello/frost round-trips with the directory's K_server shares via directoryNodeStubs).
|
|
666
|
+
const result = await signer.participateInCeremony(`seal:${sidHex}`, tbs, "cello-frost-seal-v1");
|
|
667
|
+
frostSignature = result.ok ? new Uint8Array(result.signature) : null;
|
|
668
|
+
deps.logger.info("session.seal.ceremony.participated", { agentName: deps.agentName, sessionId: sidHex, ok: result.ok });
|
|
669
|
+
}
|
|
670
|
+
catch (err) {
|
|
671
|
+
deps.logger.warn("session.seal.ceremony.failed", {
|
|
672
|
+
agentName: deps.agentName,
|
|
673
|
+
sessionId: sidHex,
|
|
674
|
+
detail: extractErrorMessage(err),
|
|
675
|
+
});
|
|
676
|
+
deps.recordSealFailure(deps.agentName, sidHex, "seal_ceremony_threw", "unresolved");
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
if (!frostSignature) {
|
|
680
|
+
/**
|
|
681
|
+
* ⚠️ THIS WAS `if (!frostSignature) return;` WITH NO LOG AND NO RECORD —
|
|
682
|
+
* `DOD-M15-SEALPARTIES-1`.
|
|
683
|
+
*
|
|
684
|
+
* It is where a seal lands when the FROST ceremony produces nothing, and requiring the
|
|
685
|
+
* co-signing directories to judge the leaves makes it reachable for a NEW and important
|
|
686
|
+
* reason: a holder looked at the record, decided it does not support the root, and declined.
|
|
687
|
+
* That is the strongest signal this system produces, and its entire trace was a bare return.
|
|
688
|
+
*
|
|
689
|
+
* The refusing node's own reason is on the coordinating side too — `network-directory-node`
|
|
690
|
+
* logs `frost.directory.sign.refused` per node with what that node said — because a
|
|
691
|
+
* threshold failure is a count, and the count does not say WHY any particular holder said
|
|
692
|
+
* no.
|
|
693
|
+
*/
|
|
694
|
+
deps.logger.error("session.seal.ceremony.no_signature", {
|
|
695
|
+
agentName: deps.agentName,
|
|
696
|
+
sessionId: sidHex,
|
|
697
|
+
cosignRefusals: [...cosignRefusals].sort(),
|
|
698
|
+
impact: "the seal FROST ceremony ended with no signature, so this session has no certificate " +
|
|
699
|
+
"and nothing was signed with this agent's key. Enough share-holding directories " +
|
|
700
|
+
"declined or were unreachable that the threshold was not met.",
|
|
701
|
+
guidance: "Look for frost.directory.sign.refused in this daemon's log — each line names one " +
|
|
702
|
+
"directory and the reason it gave. A SEAL_ROOT_UNSUPPORTED there means a holder rebuilt " +
|
|
703
|
+
"the root from the leaves and got a different answer, which is a fault in the verifying " +
|
|
704
|
+
"directory or the relay, not in this agent. Do NOT force-abandon: that forfeits the " +
|
|
705
|
+
"receipt permanently.",
|
|
706
|
+
});
|
|
707
|
+
deps.recordSealFailure(deps.agentName, sidHex, cosignRefusals.size > 0
|
|
708
|
+
? `seal_cosigners_refused:${[...cosignRefusals].sort().join(",")}`
|
|
709
|
+
: "seal_ceremony_threshold_not_met", "unresolved");
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
await sendSealFrostSignature(deps, sessionId, sidHex, frostSignature);
|
|
713
|
+
})();
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* DOD-SENDRAW-1: deliver the co-signed seal FROST signature to the directory, branching on the
|
|
718
|
+
* seam's RESOLVED result. The production seam (transport SignalingManager.sendRaw) never throws —
|
|
719
|
+
* it resolves {ok:false, reason} on every failure — so the old try/catch logged `.sent` for a
|
|
720
|
+
* signature that never left the machine, inside the non-repudiation ceremony, and the failure
|
|
721
|
+
* event was unreachable. Exported so the send contract is testable without a live FROST ceremony.
|
|
722
|
+
*/
|
|
723
|
+
export async function sendSealFrostSignature(deps, sessionId, sidHex, frostSignature) {
|
|
724
|
+
try {
|
|
725
|
+
const res = await deps.signaling.sendRaw({ type: "seal_frost_signature", session_id: sessionId, frost_signature: frostSignature });
|
|
726
|
+
if (res.ok) {
|
|
727
|
+
deps.logger.info("session.seal.frost.signature.sent", { agentName: deps.agentName, sessionId: sidHex });
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
deps.logger.warn("session.seal.frost.signature.send.failed", {
|
|
731
|
+
agentName: deps.agentName,
|
|
732
|
+
sessionId: sidHex,
|
|
733
|
+
detail: res.reason ?? "send_not_ok",
|
|
734
|
+
...(res.guidance ? { guidance: res.guidance } : {}),
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
catch (err) {
|
|
739
|
+
deps.logger.warn("session.seal.frost.signature.send.failed", {
|
|
740
|
+
agentName: deps.agentName,
|
|
741
|
+
sessionId: sidHex,
|
|
742
|
+
detail: extractErrorMessage(err),
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* SESSION-002 (DOD-SEAL-3): verify a unilateral seal certificate WITHOUT trusting the
|
|
748
|
+
* channel. Rebuilds the canonical seal TBS from the cert fields and verifies the signature
|
|
749
|
+
* against a key trusted independently of the delivering frame: the session primary_pubkey
|
|
750
|
+
* (commitments[0] of this agent's FROST share) for 'frost'. A channel-swapped sealed_root
|
|
751
|
+
* (or any TBS-bound field) fails this check (SI-003).
|
|
752
|
+
*
|
|
753
|
+
* 'single' is not a second variant this function is missing — it is a DOWNGRADE, refused by name
|
|
754
|
+
* before a session exists (`assignment_signature_type_downgraded`, assignment-verify.ts, checked
|
|
755
|
+
* against the directory's only producer of `signature_type`). A cert carrying it is a shape no
|
|
756
|
+
* honest peer can produce, so the branch below refuses rather than verifying. Do not "finish" it
|
|
757
|
+
* by adding a manifest-key path: that would make the downgrade verifiable instead of refused,
|
|
758
|
+
* which is the outcome the upstream check exists to prevent.
|
|
759
|
+
*/
|
|
760
|
+
export async function verifyUnilateralCertificate(deps, cert) {
|
|
761
|
+
const tbs = buildSealTbs(cert.sessionId, cert.sealedRoot, cert.leafCount, cert.closeTimestamp);
|
|
762
|
+
if (cert.signatureType !== "frost") {
|
|
763
|
+
// 'single' is a DOWNGRADE, not an unfinished path. A pre-DKG single-key assignment is refused
|
|
764
|
+
// by name upstream (`assignment_signature_type_downgraded`, assignment-verify.ts), so a cert
|
|
765
|
+
// reaching here with one is a shape that should never arrive. Refusing is the correct end state;
|
|
766
|
+
// there is nothing to wire.
|
|
767
|
+
return { ok: false, reason: "single_key_verification_unsupported" };
|
|
768
|
+
}
|
|
769
|
+
const share = await deps.persistence.loadActiveFrostKeyShare();
|
|
770
|
+
if (!share)
|
|
771
|
+
return { ok: false, reason: "no_frost_share" };
|
|
772
|
+
let primaryPubkey = null;
|
|
773
|
+
try {
|
|
774
|
+
const dc = decode(Buffer.from(share.commitmentsCbor));
|
|
775
|
+
if (Array.isArray(dc) && dc.length > 0) {
|
|
776
|
+
const c0 = dc[0];
|
|
777
|
+
primaryPubkey = c0 instanceof Uint8Array ? c0 : Buffer.isBuffer(c0) ? new Uint8Array(c0) : null;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
catch (err) {
|
|
781
|
+
deps.logger.warn("session.unilateral.certificate.share.decode.failed", {
|
|
782
|
+
agentPubkey: deps.agentPubkeyHex,
|
|
783
|
+
detail: extractErrorMessage(err),
|
|
784
|
+
});
|
|
785
|
+
return { ok: false, reason: "share_decode_failed" };
|
|
786
|
+
}
|
|
787
|
+
if (!primaryPubkey || primaryPubkey.length !== 32)
|
|
788
|
+
return { ok: false, reason: "no_primary_pubkey" };
|
|
789
|
+
const verifier = new FrostThresholdSigner({ threshold: 1, participants: 1 }, Buffer.from(deps.agentPubkeyHex, "hex"));
|
|
790
|
+
const valid = verifier.verifySignature(cert.frostSignature, tbs, "cello-frost-seal-v1", primaryPubkey);
|
|
791
|
+
return valid ? { ok: true } : { ok: false, reason: "signature_invalid" };
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* M7 legibility-TBS-binding: verify a BILATERAL session_sealed certificate's signature over the
|
|
795
|
+
* legibility-bound TBS, channel-independently.
|
|
796
|
+
*
|
|
797
|
+
* KEY STRUCTURE (why verifiability is asymmetric TODAY): the seal's FROST signature is produced by
|
|
798
|
+
* the group key (commitments[0] of the DKG share) of whichever party CLOSED THE SESSION FIRST — the
|
|
799
|
+
* directory designates the sender of the first SEAL ctrl leaf as the "seal initiator" and signs
|
|
800
|
+
* against that party's primary (directory-node.ts). This is NOT a fixed initiator/responder role:
|
|
801
|
+
* either the session initiator or the responder can be the first closer.
|
|
802
|
+
*
|
|
803
|
+
* A party can channel-independently verify here only against a group primary it HOLDS locally:
|
|
804
|
+
* - its OWN primary — loaded from its own DKG share (`signer_pubkey === own primary`); or
|
|
805
|
+
* - the counterparty's primary — recorded via recordCounterpartyPrimary (see below).
|
|
806
|
+
* It then verifies the FROST signature over `buildSealTbs ‖ legibilityHash`. A tampered legibility
|
|
807
|
+
* (answered / content_frontier_seq / attestation_mode — carried unsigned on the frame) changes the
|
|
808
|
+
* hash → the signature fails → REJECT.
|
|
809
|
+
*
|
|
810
|
+
* When the signer's key is NOT held locally, the party ACCEPTS (`verified:false`, with a `reason`).
|
|
811
|
+
* This is sound for the LIVE path: session_sealed arrives over the daemon↔directory libp2p Noise
|
|
812
|
+
* channel (authenticated + encrypted), so it is not MITM-tamperable in transit; the binding's
|
|
813
|
+
* primary value is OUT-OF-BAND (any holder of the signer's primary — e.g. an arbitrator — can verify
|
|
814
|
+
* an exported cert's legibility).
|
|
815
|
+
*
|
|
816
|
+
* SYMMETRY: both closing orders verify locally, and it takes BOTH bindings to stay that way. The
|
|
817
|
+
* initiator learns the responder's primary from `participant_b_primary_pubkey` with a binding
|
|
818
|
+
* signed by participant_b's own K_local, recorded by `initiate-session-handler.ts`; the responder
|
|
819
|
+
* learns the initiator's from `signer_pubkey` with `participant_a_key_binding`, verified before the
|
|
820
|
+
* assignment's threshold signature is checked at all and recorded by `inbound-sessions.ts`. Both
|
|
821
|
+
* are refused by name when absent or invalid (`assignment-verify.ts`).
|
|
822
|
+
*
|
|
823
|
+
* The binding, not the key, is the load-bearing part: carrying a group key alone would let a
|
|
824
|
+
* directory name one of its choosing, so a change that keeps either key and drops its binding
|
|
825
|
+
* breaks verification while appearing to work.
|
|
826
|
+
*
|
|
827
|
+
* `signer_key_not_held` is therefore NOT the ordinary responder-first outcome. It remains reachable
|
|
828
|
+
* for a session row that predates the recording, or one whose assignment never reached this path,
|
|
829
|
+
* and it is the honest answer there, which is why the branch stays.
|
|
830
|
+
*
|
|
831
|
+
* `legibility` MUST be the AS-RECEIVED wire object (not a normalised copy) — the directory signed
|
|
832
|
+
* over the canonical hash of exactly what it sent.
|
|
833
|
+
*/
|
|
834
|
+
export async function verifyBilateralSealCertificate(deps, cert) {
|
|
835
|
+
// F2-a: every verified:false branch carries a `reason` so the daemon's
|
|
836
|
+
// session.sealed.signature.checked log can never read as a silently-tolerated FAILED check.
|
|
837
|
+
// A genuinely failed check takes the { ok:false, reason:"signature_invalid" } path, which the
|
|
838
|
+
// caller REJECTS (never marks sealed). verified:false is always "no key held to verify → accepted
|
|
839
|
+
// on the authenticated Noise channel", never "a check ran and failed".
|
|
840
|
+
if (cert.signatureType !== "frost")
|
|
841
|
+
return { ok: true, verified: false, reason: "non_frost_certificate" };
|
|
842
|
+
if (cert.signerPubkey.length !== 32)
|
|
843
|
+
return { ok: false, reason: "no_signer_pubkey" };
|
|
844
|
+
const signerHex = Buffer.from(cert.signerPubkey).toString("hex");
|
|
845
|
+
const share = await deps.persistence.loadActiveFrostKeyShare();
|
|
846
|
+
if (!share)
|
|
847
|
+
return { ok: true, verified: false, reason: "no_frost_share" }; // no share to verify with — accept (Noise-delivered)
|
|
848
|
+
let ownPrimary = null;
|
|
849
|
+
try {
|
|
850
|
+
const dc = decode(Buffer.from(share.commitmentsCbor));
|
|
851
|
+
if (Array.isArray(dc) && dc.length > 0) {
|
|
852
|
+
const c0 = dc[0];
|
|
853
|
+
ownPrimary = c0 instanceof Uint8Array ? c0 : Buffer.isBuffer(c0) ? new Uint8Array(c0) : null;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
catch {
|
|
857
|
+
return { ok: true, verified: false, reason: "commitments_decode_failed" };
|
|
858
|
+
}
|
|
859
|
+
if (!ownPrimary || ownPrimary.length !== 32)
|
|
860
|
+
return { ok: true, verified: false, reason: "own_primary_unavailable" };
|
|
861
|
+
// The seal is signed by the INITIATOR's primary (group) key. This party can verify against a
|
|
862
|
+
// key it holds independently: its OWN primary (when it is the initiator) or the counterparty's
|
|
863
|
+
// primary from the FROST-signed SessionAssignment (when it is the responder). SI-003: the signer
|
|
864
|
+
// must be one of these — never a key supplied only by the (untrusted) cert frame.
|
|
865
|
+
const cpHex = deps.counterpartyPrimaryHex ?? null;
|
|
866
|
+
if (signerHex === Buffer.from(ownPrimary).toString("hex")) {
|
|
867
|
+
// initiator path — verify against own primary.
|
|
868
|
+
}
|
|
869
|
+
else if (cpHex && signerHex === cpHex.toLowerCase()) {
|
|
870
|
+
// responder path — verify against the known counterparty primary.
|
|
871
|
+
}
|
|
872
|
+
else if (cpHex) {
|
|
873
|
+
// We know the counterparty primary and the signer is NEITHER participant → unknown signer.
|
|
874
|
+
return { ok: false, reason: "signer_not_a_session_participant" };
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
// We do not hold the signer's key (no counterparty primary recorded) → cannot verify; accept
|
|
878
|
+
// (the live frame arrived over the authenticated Noise channel; the binding aids out-of-band).
|
|
879
|
+
// Reachable only for a session whose assignment never carried (or never recorded) the
|
|
880
|
+
// counterparty's bound primary — a pre-038-KEYBIND row. A CURRENT session reaching here means
|
|
881
|
+
// `recordCounterpartyPrimary` did not run on either side (`initiate-session-handler.ts` for the
|
|
882
|
+
// initiator, `inbound-sessions.ts` for the responder), which is a defect, not a close order.
|
|
883
|
+
return { ok: true, verified: false, reason: "signer_key_not_held" };
|
|
884
|
+
}
|
|
885
|
+
const tbs = bindLegibilityToTbs(buildSealTbs(cert.sessionId, cert.sealedRoot, cert.leafCount, cert.closeTimestamp), cert.legibility);
|
|
886
|
+
const verifier = new FrostThresholdSigner({ threshold: 1, participants: 1 }, Buffer.from(deps.agentPubkeyHex, "hex"));
|
|
887
|
+
const valid = verifier.verifySignature(cert.frostSignature, tbs, "cello-frost-seal-v1", cert.signerPubkey);
|
|
888
|
+
return valid ? { ok: true, verified: true } : { ok: false, reason: "signature_invalid" };
|
|
889
|
+
}
|
|
890
|
+
export function wireSessionCeremonyHandler(deps) {
|
|
891
|
+
return deps.signaling.registerInboundHandler((frame) => {
|
|
892
|
+
if (frame["type"] !== "ceremony_request")
|
|
893
|
+
return;
|
|
894
|
+
void (async () => {
|
|
895
|
+
const ceremonyId = typeof frame["ceremony_id"] === "string" ? frame["ceremony_id"] : undefined;
|
|
896
|
+
const tbsRaw = frame["tbs"];
|
|
897
|
+
const tbs = tbsRaw instanceof Uint8Array ? tbsRaw : Buffer.isBuffer(tbsRaw) ? new Uint8Array(tbsRaw) : null;
|
|
898
|
+
const context = typeof frame["context"] === "string" ? frame["context"] : undefined;
|
|
899
|
+
// L3: the reply send is best-effort — a throw here must not become an unhandled
|
|
900
|
+
// rejection in this fire-and-forget handler. DOD-SENDRAW-1: the production seam never
|
|
901
|
+
// throws — it resolves {ok:false, reason} — so the failure must be read off the RESULT;
|
|
902
|
+
// catch-only made session.ceremony.reply.failed unreachable in production.
|
|
903
|
+
const reply = async (signature) => {
|
|
904
|
+
if (!ceremonyId)
|
|
905
|
+
return;
|
|
906
|
+
try {
|
|
907
|
+
const res = await deps.signaling.sendRaw({ type: "ceremony_result", ceremony_id: ceremonyId, signature });
|
|
908
|
+
if (!res.ok) {
|
|
909
|
+
deps.logger.warn("session.ceremony.reply.failed", {
|
|
910
|
+
agentName: deps.agentName,
|
|
911
|
+
detail: res.reason ?? "send_not_ok",
|
|
912
|
+
...(res.guidance ? { guidance: res.guidance } : {}),
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
catch (err) {
|
|
917
|
+
deps.logger.warn("session.ceremony.reply.failed", {
|
|
918
|
+
agentName: deps.agentName,
|
|
919
|
+
detail: extractErrorMessage(err),
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
// L1: a request with no addressable ceremony_id cannot be replied to (the reply is
|
|
924
|
+
// keyed by it) — log and drop rather than send an unkeyed result.
|
|
925
|
+
if (!ceremonyId) {
|
|
926
|
+
deps.logger.warn("session.ceremony.abort", { agentName: deps.agentName, reason: "no_ceremony_id" });
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
if (!tbs || !context) {
|
|
930
|
+
deps.logger.warn("session.ceremony.abort", { agentName: deps.agentName, reason: !tbs ? "no_tbs" : "no_context" });
|
|
931
|
+
await reply(null);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
// H1 / M1 / concurrency: reconstruct a FRESH signer (fresh directory endpoint +
|
|
935
|
+
// NetworkDirectoryNode) PER ceremony. No caching — so signaling reconnecting to a
|
|
936
|
+
// different directory node is picked up, a transient reconstruction failure retries
|
|
937
|
+
// on the next request, and concurrent ceremonies never share one signer's FROST
|
|
938
|
+
// state. (storeDkgResult is idempotent for the same share; reconstruction is cheap.)
|
|
939
|
+
const signer = await reconstructThresholdSigner(deps);
|
|
940
|
+
if (!signer) {
|
|
941
|
+
deps.logger.warn("session.ceremony.abort", { agentName: deps.agentName, reason: "no_signer" });
|
|
942
|
+
await reply(null);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
try {
|
|
946
|
+
const result = await signer.participateInCeremony(ceremonyId, tbs, context);
|
|
947
|
+
deps.logger.info("session.ceremony.participated", {
|
|
948
|
+
agentName: deps.agentName,
|
|
949
|
+
ceremonyId: ceremonyId.slice(0, 16),
|
|
950
|
+
ok: result.ok,
|
|
951
|
+
});
|
|
952
|
+
await reply(result.ok ? new Uint8Array(result.signature) : null);
|
|
953
|
+
}
|
|
954
|
+
catch (err) {
|
|
955
|
+
deps.logger.warn("session.ceremony.failed", {
|
|
956
|
+
agentName: deps.agentName,
|
|
957
|
+
detail: extractErrorMessage(err),
|
|
958
|
+
});
|
|
959
|
+
await reply(null);
|
|
960
|
+
}
|
|
961
|
+
})();
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
//# sourceMappingURL=session-ceremony.js.map
|