keri-ts 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -2
- package/esm/keri/npm/src/acdc/authoring.js +195 -0
- package/esm/keri/npm/src/acdc/chaining.js +223 -89
- package/esm/keri/npm/src/acdc/custody.js +164 -0
- package/esm/keri/npm/src/acdc/dhking.js +244 -32
- package/esm/keri/npm/src/acdc/observing.js +2 -2
- package/esm/keri/npm/src/acdc/regbasing.js +30 -29
- package/esm/keri/npm/src/acdc/regengine.js +4 -6
- package/esm/keri/npm/src/acdc/registering.js +13 -10
- package/esm/keri/npm/src/acdc/registraring.js +4 -9
- package/esm/keri/npm/src/acdc/salting.js +143 -26
- package/esm/keri/npm/src/acdc/scheming.js +93 -54
- package/esm/keri/npm/src/acdc/unblinding.js +120 -99
- package/esm/keri/npm/src/app/bootstrap/authenticating.js +4 -6
- package/esm/keri/npm/src/app/bootstrap/oobi-resolving.js +41 -0
- package/esm/keri/npm/src/app/bootstrap/oobiery.js +5 -7
- package/esm/keri/npm/src/app/credentials/credential-revoking.js +1 -0
- package/esm/keri/npm/src/app/credentials/credential-workflows.js +2 -0
- package/esm/keri/npm/src/app/credentials/registry-settling.js +44 -0
- package/esm/keri/npm/src/app/credentials/root-replicating.js +131 -0
- package/esm/keri/npm/src/app/credentials/root-replicator.js +198 -0
- package/esm/keri/npm/src/app/credentials/tel-completion.js +36 -0
- package/esm/keri/npm/src/app/credentials/verifying.js +12 -3
- package/esm/keri/npm/src/app/delivery/forwarding.js +64 -9
- package/esm/keri/npm/src/app/exchanges/exchanging.js +24 -15
- package/esm/keri/npm/src/app/identity/challenging.js +50 -0
- package/esm/keri/npm/src/app/identity/configing.js +17 -43
- package/esm/keri/npm/src/app/identity/delegating.js +77 -77
- package/esm/keri/npm/src/app/identity/delegation-approval.js +333 -0
- package/esm/keri/npm/src/app/identity/event-completion.js +154 -0
- package/esm/keri/npm/src/app/identity/habbing.js +183 -41
- package/esm/keri/npm/src/app/identity/keeping.js +78 -5
- package/esm/keri/npm/src/app/identity/lmdb-habery.js +12 -0
- package/esm/keri/npm/src/app/ipex/group-ipex.js +327 -0
- package/esm/keri/npm/src/app/ipex/group-issuance.js +902 -0
- package/esm/keri/npm/src/app/ipex/ipex-admitting.js +120 -0
- package/esm/keri/npm/src/app/ipex/ipex-conversation.js +197 -0
- package/esm/keri/npm/src/app/ipex/ipex-discloser.js +591 -0
- package/esm/keri/npm/src/app/ipex/ipex-granting.js +93 -0
- package/esm/keri/npm/src/app/ipex/ipex-graph.js +7 -70
- package/esm/keri/npm/src/app/ipex/ipex-grouping.js +42 -16
- package/esm/keri/npm/src/app/ipex/ipex-v2.js +21 -5
- package/esm/keri/npm/src/app/ipex/ipexing.js +1 -1
- package/esm/keri/npm/src/app/ipex/issuance.js +888 -0
- package/esm/keri/npm/src/app/ipex/pending-presentations.js +46 -0
- package/esm/keri/npm/src/app/ipex/presentation-files.js +200 -0
- package/esm/keri/npm/src/app/ipex/presenting.js +401 -0
- package/esm/keri/npm/src/app/ipex/receive-issuance.js +86 -0
- package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +660 -0
- package/esm/keri/npm/src/app/mailbox/ipex-arrival.js +103 -0
- package/esm/keri/npm/src/app/mailbox/kel-publisher.js +322 -0
- package/esm/keri/npm/src/app/mailbox/kel-publishing.js +65 -0
- package/esm/keri/npm/src/app/mailbox/kel-submission.js +24 -0
- package/esm/keri/npm/src/app/mailbox/mailbox-admin.js +208 -0
- package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +212 -47
- package/esm/keri/npm/src/app/mailbox/mailboxing.js +15 -14
- package/esm/keri/npm/src/app/multisig/counseling.js +482 -0
- package/esm/keri/npm/src/app/multisig/group-members.js +32 -0
- package/esm/keri/npm/src/app/multisig/grouping.js +4 -3
- package/esm/keri/npm/src/app/multisig/multisig-workflows.js +101 -141
- package/esm/keri/npm/src/app/multisig/proposals.js +281 -0
- package/esm/keri/npm/src/app/multisig/proposing.js +122 -0
- package/esm/keri/npm/src/app/notifications/notifying.js +5 -9
- package/esm/keri/npm/src/app/notifications/signaling.js +5 -5
- package/esm/keri/npm/src/app/protocol/parsering.js +26 -1
- package/esm/keri/npm/src/app/protocol/protocol-processing.js +44 -6
- package/esm/keri/npm/src/app/queries/query-workflows.js +98 -0
- package/esm/keri/npm/src/app/queries/witness-inquisitor.js +2 -2
- package/esm/keri/npm/src/app/runtime/agent-runtime.js +113 -65
- package/esm/keri/npm/src/app/runtime/cue-runtime.js +3 -6
- package/esm/keri/npm/src/app/runtime/delivery-outbox.js +87 -0
- package/esm/keri/npm/src/app/runtime/doing.js +17 -0
- package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +207 -0
- package/esm/keri/npm/src/app/runtime/operation-owners.js +151 -0
- package/esm/keri/npm/src/app/runtime/retry-backoff.js +93 -0
- package/esm/keri/npm/src/app/runtime/workflow-contract.js +80 -0
- package/esm/keri/npm/src/app/transport/byte-source.js +6 -42
- package/esm/keri/npm/src/app/transport/cesr-egress.js +77 -13
- package/esm/keri/npm/src/app/transport/file-bytes.js +41 -0
- package/esm/keri/npm/src/app/transport/http-client.js +25 -6
- package/esm/keri/npm/src/app/transport/http-messenger.js +14 -9
- package/esm/keri/npm/src/app/transport/message-source.js +1 -1
- package/esm/keri/npm/src/app/transport/messengering.js +3 -4
- package/esm/keri/npm/src/app/transport/node-http-client.js +21 -0
- package/esm/keri/npm/src/app/transport/tcp-dialer.js +14 -0
- package/esm/keri/npm/src/app/witness/http-endpoints.js +4 -4
- package/esm/keri/npm/src/app/witness/receipt-client.js +2 -2
- package/esm/keri/npm/src/cli/common/context.js +2 -2
- package/esm/keri/npm/src/cli/common/event-completion.js +49 -0
- package/esm/keri/npm/src/cli/common/existing.js +3 -5
- package/esm/keri/npm/src/cli/common/runtime-workers.js +23 -0
- package/esm/keri/npm/src/cli/credentials/ipex.js +159 -191
- package/esm/keri/npm/src/cli/credentials/vc.js +53 -72
- package/esm/keri/npm/src/cli/endpoints/did.js +12 -3
- package/esm/keri/npm/src/cli/endpoints/oobi-clean.js +4 -3
- package/esm/keri/npm/src/cli/endpoints/oobi.js +12 -15
- package/esm/keri/npm/src/cli/identity/challenge.js +9 -35
- package/esm/keri/npm/src/cli/identity/delegate.js +81 -258
- package/esm/keri/npm/src/cli/identity/incept.js +17 -34
- package/esm/keri/npm/src/cli/identity/init.js +4 -3
- package/esm/keri/npm/src/cli/identity/interact.js +7 -19
- package/esm/keri/npm/src/cli/identity/rotate.js +10 -38
- package/esm/keri/npm/src/cli/index.js +3 -1
- package/esm/keri/npm/src/cli/messaging/exchange.js +2 -2
- package/esm/keri/npm/src/cli/messaging/group-join.js +79 -0
- package/esm/keri/npm/src/cli/messaging/group-wait.js +88 -0
- package/esm/keri/npm/src/cli/messaging/multisig.js +187 -250
- package/esm/keri/npm/src/cli/messaging/root-copy-lines.js +31 -0
- package/esm/keri/npm/src/cli/tools/annotate.js +2 -1
- package/esm/keri/npm/src/cli/tools/benchmark.js +2 -1
- package/esm/keri/npm/src/cli/tools/db-dump.js +1 -4
- package/esm/keri/npm/src/core/bytes.js +9 -0
- package/esm/keri/npm/src/core/kel/delegation-ancestry.js +92 -0
- package/esm/keri/npm/src/core/kel/eventing.js +67 -12
- package/esm/keri/npm/src/core/kel/kever.js +11 -9
- package/esm/keri/npm/src/core/mailbox/kram-policy.js +41 -9
- package/esm/keri/npm/src/core/mailbox/kram-pruning.js +15 -22
- package/esm/keri/npm/src/core/mailbox/kram-staging.js +2 -2
- package/esm/keri/npm/src/core/mailbox/kraming.js +2 -0
- package/esm/keri/npm/src/core/records.js +23 -0
- package/esm/keri/npm/src/core/routing.js +15 -2
- package/esm/keri/npm/src/db/basing.js +183 -205
- package/esm/keri/npm/src/db/core/dber.js +1062 -0
- package/esm/keri/npm/src/db/core/index.js +4 -2
- package/esm/keri/npm/src/db/core/indexeddb-persistence.js +221 -0
- package/esm/keri/npm/src/db/core/lmdb-opener.js +30 -0
- package/esm/keri/npm/src/db/core/lmdber.js +199 -1067
- package/esm/keri/npm/src/db/core/memstore.js +532 -0
- package/esm/keri/npm/src/db/core/path-manager.js +109 -223
- package/esm/keri/npm/src/db/core/store-owner.js +104 -0
- package/esm/keri/npm/src/db/core/webdber.js +252 -0
- package/esm/keri/npm/src/db/escrowing.js +2 -2
- package/esm/keri/npm/src/db/exchange/exchange-nests.js +3 -2
- package/esm/keri/npm/src/db/indexeddb.js +98 -0
- package/esm/keri/npm/src/db/keeping.js +38 -123
- package/esm/keri/npm/src/db/koming.js +1 -1
- package/esm/keri/npm/src/db/lmdb-stores.js +68 -0
- package/esm/keri/npm/src/db/lmdb.js +6 -0
- package/esm/keri/npm/src/db/mailbox/mailboxing.js +12 -65
- package/esm/keri/npm/src/db/noting.js +11 -55
- package/esm/keri/npm/src/db/reger.js +43 -105
- package/esm/keri/npm/src/db/replay/witness-replay.js +2 -20
- package/esm/keri/npm/src/db/store-lock.js +150 -0
- package/esm/keri/npm/src/db/subing.js +1 -1
- package/esm/keri/npm/src/npm/db-indexeddb.browser.js +2 -0
- package/esm/keri/npm/src/npm/db-indexeddb.js +3 -0
- package/esm/keri/npm/src/npm/db-lmdb.js +3 -0
- package/esm/keri/npm/src/npm/db.browser.js +2 -0
- package/esm/keri/npm/src/npm/index.browser.js +9 -0
- package/esm/keri/npm/src/npm/runtime-node.js +3 -0
- package/esm/keri/npm/src/npm/runtime-web.browser.js +2 -0
- package/esm/keri/npm/src/npm/runtime-web.js +3 -0
- package/esm/keri/npm/src/npm/runtime.browser.js +2 -0
- package/esm/keri/npm/src/runtime/index.js +58 -12
- package/esm/keri/npm/src/runtime/node.js +14 -0
- package/esm/keri/npm/src/runtime/web/output-barrier.js +47 -0
- package/esm/keri/npm/src/runtime/web/persistent-storage.js +37 -0
- package/esm/keri/npm/src/runtime/web.js +10 -0
- package/esm/keri/npm/src/vdr/eventing.js +1 -1
- package/esm/keri/npm/src/vdr/tel-publication.js +19 -3
- package/esm/keri/npm/src/version.js +2 -2
- package/package.json +24 -4
- package/types/acdc/authoring.d.ts +54 -0
- package/types/acdc/authoring.d.ts.map +1 -0
- package/types/acdc/chaining.d.ts +56 -6
- package/types/acdc/chaining.d.ts.map +1 -1
- package/types/acdc/custody.d.ts +77 -0
- package/types/acdc/custody.d.ts.map +1 -0
- package/types/acdc/dhking.d.ts +94 -3
- package/types/acdc/dhking.d.ts.map +1 -1
- package/types/acdc/regbasing.d.ts +11 -6
- package/types/acdc/regbasing.d.ts.map +1 -1
- package/types/acdc/regengine.d.ts.map +1 -1
- package/types/acdc/registering.d.ts +8 -4
- package/types/acdc/registering.d.ts.map +1 -1
- package/types/acdc/registraring.d.ts.map +1 -1
- package/types/acdc/salting.d.ts +59 -7
- package/types/acdc/salting.d.ts.map +1 -1
- package/types/acdc/scheming.d.ts +2 -0
- package/types/acdc/scheming.d.ts.map +1 -1
- package/types/acdc/unblinding.d.ts +58 -19
- package/types/acdc/unblinding.d.ts.map +1 -1
- package/types/app/bootstrap/authenticating.d.ts +3 -1
- package/types/app/bootstrap/authenticating.d.ts.map +1 -1
- package/types/app/bootstrap/oobi-resolving.d.ts +92 -0
- package/types/app/bootstrap/oobi-resolving.d.ts.map +1 -0
- package/types/app/bootstrap/oobiery.d.ts +3 -1
- package/types/app/bootstrap/oobiery.d.ts.map +1 -1
- package/types/app/credentials/credential-revoking.d.ts +3 -0
- package/types/app/credentials/credential-revoking.d.ts.map +1 -1
- package/types/app/credentials/credential-workflows.d.ts +5 -0
- package/types/app/credentials/credential-workflows.d.ts.map +1 -1
- package/types/app/credentials/registry-settling.d.ts +85 -0
- package/types/app/credentials/registry-settling.d.ts.map +1 -0
- package/types/app/credentials/root-replicating.d.ts +97 -0
- package/types/app/credentials/root-replicating.d.ts.map +1 -0
- package/types/app/credentials/root-replicator.d.ts +105 -0
- package/types/app/credentials/root-replicator.d.ts.map +1 -0
- package/types/app/credentials/tel-completion.d.ts +55 -0
- package/types/app/credentials/tel-completion.d.ts.map +1 -0
- package/types/app/credentials/verifying.d.ts +2 -1
- package/types/app/credentials/verifying.d.ts.map +1 -1
- package/types/app/delivery/forwarding.d.ts +16 -0
- package/types/app/delivery/forwarding.d.ts.map +1 -1
- package/types/app/exchanges/exchanging.d.ts +2 -0
- package/types/app/exchanges/exchanging.d.ts.map +1 -1
- package/types/app/identity/challenging.d.ts +54 -0
- package/types/app/identity/challenging.d.ts.map +1 -1
- package/types/app/identity/configing.d.ts +7 -5
- package/types/app/identity/configing.d.ts.map +1 -1
- package/types/app/identity/delegating.d.ts +21 -4
- package/types/app/identity/delegating.d.ts.map +1 -1
- package/types/app/identity/delegation-approval.d.ts +228 -0
- package/types/app/identity/delegation-approval.d.ts.map +1 -0
- package/types/app/identity/event-completion.d.ts +151 -0
- package/types/app/identity/event-completion.d.ts.map +1 -0
- package/types/app/identity/habbing.d.ts +90 -7
- package/types/app/identity/habbing.d.ts.map +1 -1
- package/types/app/identity/keeping.d.ts +50 -4
- package/types/app/identity/keeping.d.ts.map +1 -1
- package/types/app/identity/lmdb-habery.d.ts +6 -0
- package/types/app/identity/lmdb-habery.d.ts.map +1 -0
- package/types/app/ipex/group-ipex.d.ts +247 -0
- package/types/app/ipex/group-ipex.d.ts.map +1 -0
- package/types/app/ipex/group-issuance.d.ts +281 -0
- package/types/app/ipex/group-issuance.d.ts.map +1 -0
- package/types/app/ipex/ipex-admitting.d.ts +47 -0
- package/types/app/ipex/ipex-admitting.d.ts.map +1 -0
- package/types/app/ipex/ipex-conversation.d.ts +195 -0
- package/types/app/ipex/ipex-conversation.d.ts.map +1 -0
- package/types/app/ipex/ipex-discloser.d.ts +156 -0
- package/types/app/ipex/ipex-discloser.d.ts.map +1 -0
- package/types/app/ipex/ipex-granting.d.ts +145 -0
- package/types/app/ipex/ipex-granting.d.ts.map +1 -0
- package/types/app/ipex/ipex-graph.d.ts +4 -4
- package/types/app/ipex/ipex-graph.d.ts.map +1 -1
- package/types/app/ipex/ipex-grouping.d.ts +18 -0
- package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
- package/types/app/ipex/ipex-v2.d.ts +11 -2
- package/types/app/ipex/ipex-v2.d.ts.map +1 -1
- package/types/app/ipex/ipexing.d.ts +3 -0
- package/types/app/ipex/ipexing.d.ts.map +1 -1
- package/types/app/ipex/issuance.d.ts +443 -0
- package/types/app/ipex/issuance.d.ts.map +1 -0
- package/types/app/ipex/pending-presentations.d.ts +25 -0
- package/types/app/ipex/pending-presentations.d.ts.map +1 -0
- package/types/app/ipex/presentation-files.d.ts +47 -0
- package/types/app/ipex/presentation-files.d.ts.map +1 -0
- package/types/app/ipex/presenting.d.ts +298 -0
- package/types/app/ipex/presenting.d.ts.map +1 -0
- package/types/app/ipex/receive-issuance.d.ts +99 -0
- package/types/app/ipex/receive-issuance.d.ts.map +1 -0
- package/types/app/ipex/unblinding-workflow.d.ts +255 -0
- package/types/app/ipex/unblinding-workflow.d.ts.map +1 -0
- package/types/app/mailbox/ipex-arrival.d.ts +104 -0
- package/types/app/mailbox/ipex-arrival.d.ts.map +1 -0
- package/types/app/mailbox/kel-publisher.d.ts +141 -0
- package/types/app/mailbox/kel-publisher.d.ts.map +1 -0
- package/types/app/mailbox/kel-publishing.d.ts +70 -0
- package/types/app/mailbox/kel-publishing.d.ts.map +1 -0
- package/types/app/mailbox/kel-submission.d.ts +18 -0
- package/types/app/mailbox/kel-submission.d.ts.map +1 -0
- package/types/app/mailbox/mailbox-admin.d.ts +113 -0
- package/types/app/mailbox/mailbox-admin.d.ts.map +1 -0
- package/types/app/mailbox/mailbox-poller.d.ts +92 -3
- package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
- package/types/app/mailbox/mailboxing.d.ts +4 -1
- package/types/app/mailbox/mailboxing.d.ts.map +1 -1
- package/types/app/multisig/counseling.d.ts +196 -0
- package/types/app/multisig/counseling.d.ts.map +1 -0
- package/types/app/multisig/group-members.d.ts +20 -0
- package/types/app/multisig/group-members.d.ts.map +1 -1
- package/types/app/multisig/grouping.d.ts +39 -20
- package/types/app/multisig/grouping.d.ts.map +1 -1
- package/types/app/multisig/multisig-workflows.d.ts +93 -23
- package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
- package/types/app/multisig/proposals.d.ts +129 -0
- package/types/app/multisig/proposals.d.ts.map +1 -0
- package/types/app/multisig/proposing.d.ts +125 -0
- package/types/app/multisig/proposing.d.ts.map +1 -0
- package/types/app/notifications/notifying.d.ts +1 -1
- package/types/app/notifications/notifying.d.ts.map +1 -1
- package/types/app/notifications/signaling.d.ts +3 -1
- package/types/app/notifications/signaling.d.ts.map +1 -1
- package/types/app/protocol/parsering.d.ts +16 -1
- package/types/app/protocol/parsering.d.ts.map +1 -1
- package/types/app/protocol/protocol-processing.d.ts +9 -1
- package/types/app/protocol/protocol-processing.d.ts.map +1 -1
- package/types/app/queries/query-workflows.d.ts +98 -0
- package/types/app/queries/query-workflows.d.ts.map +1 -0
- package/types/app/runtime/agent-runtime.d.ts +79 -25
- package/types/app/runtime/agent-runtime.d.ts.map +1 -1
- package/types/app/runtime/cue-runtime.d.ts +2 -1
- package/types/app/runtime/cue-runtime.d.ts.map +1 -1
- package/types/app/runtime/delivery-outbox.d.ts +68 -0
- package/types/app/runtime/delivery-outbox.d.ts.map +1 -0
- package/types/app/runtime/doing.d.ts +27 -0
- package/types/app/runtime/doing.d.ts.map +1 -0
- package/types/app/runtime/ipex-auxiliaries.d.ts +74 -0
- package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -0
- package/types/app/runtime/operation-owners.d.ts +137 -0
- package/types/app/runtime/operation-owners.d.ts.map +1 -0
- package/types/app/runtime/retry-backoff.d.ts +49 -0
- package/types/app/runtime/retry-backoff.d.ts.map +1 -0
- package/types/app/runtime/workflow-contract.d.ts +79 -0
- package/types/app/runtime/workflow-contract.d.ts.map +1 -0
- package/types/app/transport/byte-source.d.ts +13 -10
- package/types/app/transport/byte-source.d.ts.map +1 -1
- package/types/app/transport/cesr-egress.d.ts +21 -7
- package/types/app/transport/cesr-egress.d.ts.map +1 -1
- package/types/app/transport/file-bytes.d.ts +11 -0
- package/types/app/transport/file-bytes.d.ts.map +1 -0
- package/types/app/transport/http-client.d.ts +3 -0
- package/types/app/transport/http-client.d.ts.map +1 -1
- package/types/app/transport/http-messenger.d.ts +15 -10
- package/types/app/transport/http-messenger.d.ts.map +1 -1
- package/types/app/transport/message-source.d.ts +1 -1
- package/types/app/transport/messengering.d.ts +2 -2
- package/types/app/transport/messengering.d.ts.map +1 -1
- package/types/app/transport/node-http-client.d.ts +10 -0
- package/types/app/transport/node-http-client.d.ts.map +1 -0
- package/types/app/transport/tcp-dialer.d.ts +21 -0
- package/types/app/transport/tcp-dialer.d.ts.map +1 -0
- package/types/cli/common/event-completion.d.ts +26 -0
- package/types/cli/common/event-completion.d.ts.map +1 -0
- package/types/cli/common/existing.d.ts.map +1 -1
- package/types/cli/common/runtime-workers.d.ts +23 -0
- package/types/cli/common/runtime-workers.d.ts.map +1 -0
- package/types/cli/credentials/ipex.d.ts.map +1 -1
- package/types/cli/credentials/vc.d.ts +1 -1
- package/types/cli/credentials/vc.d.ts.map +1 -1
- package/types/cli/endpoints/did.d.ts.map +1 -1
- package/types/cli/endpoints/oobi-clean.d.ts.map +1 -1
- package/types/cli/endpoints/oobi.d.ts +3 -1
- package/types/cli/endpoints/oobi.d.ts.map +1 -1
- package/types/cli/identity/challenge.d.ts +1 -1
- package/types/cli/identity/challenge.d.ts.map +1 -1
- package/types/cli/identity/delegate.d.ts +14 -1
- package/types/cli/identity/delegate.d.ts.map +1 -1
- package/types/cli/identity/incept.d.ts.map +1 -1
- package/types/cli/identity/init.d.ts.map +1 -1
- package/types/cli/identity/interact.d.ts.map +1 -1
- package/types/cli/identity/rotate.d.ts.map +1 -1
- package/types/cli/index.d.ts +4 -2
- package/types/cli/index.d.ts.map +1 -1
- package/types/cli/messaging/group-join.d.ts +53 -0
- package/types/cli/messaging/group-join.d.ts.map +1 -0
- package/types/cli/messaging/group-wait.d.ts +34 -0
- package/types/cli/messaging/group-wait.d.ts.map +1 -0
- package/types/cli/messaging/multisig.d.ts +36 -4
- package/types/cli/messaging/multisig.d.ts.map +1 -1
- package/types/cli/messaging/root-copy-lines.d.ts +39 -0
- package/types/cli/messaging/root-copy-lines.d.ts.map +1 -0
- package/types/cli/tools/annotate.d.ts.map +1 -1
- package/types/cli/tools/benchmark.d.ts.map +1 -1
- package/types/cli/tools/db-dump.d.ts.map +1 -1
- package/types/core/bytes.d.ts +2 -0
- package/types/core/bytes.d.ts.map +1 -1
- package/types/core/cues.d.ts +11 -0
- package/types/core/cues.d.ts.map +1 -1
- package/types/core/kel/delegation-ancestry.d.ts +41 -0
- package/types/core/kel/delegation-ancestry.d.ts.map +1 -0
- package/types/core/kel/eventing.d.ts.map +1 -1
- package/types/core/kel/kever.d.ts +5 -4
- package/types/core/kel/kever.d.ts.map +1 -1
- package/types/core/mailbox/kram-policy.d.ts +14 -0
- package/types/core/mailbox/kram-policy.d.ts.map +1 -1
- package/types/core/mailbox/kram-pruning.d.ts +1 -3
- package/types/core/mailbox/kram-pruning.d.ts.map +1 -1
- package/types/core/mailbox/kraming.d.ts +1 -1
- package/types/core/mailbox/kraming.d.ts.map +1 -1
- package/types/core/records.d.ts +61 -0
- package/types/core/records.d.ts.map +1 -1
- package/types/core/routing.d.ts +6 -0
- package/types/core/routing.d.ts.map +1 -1
- package/types/db/basing.d.ts +22 -25
- package/types/db/basing.d.ts.map +1 -1
- package/types/db/core/dber.d.ts +505 -0
- package/types/db/core/dber.d.ts.map +1 -0
- package/types/db/core/index.d.ts +4 -2
- package/types/db/core/index.d.ts.map +1 -1
- package/types/db/core/indexeddb-persistence.d.ts +59 -0
- package/types/db/core/indexeddb-persistence.d.ts.map +1 -0
- package/types/db/core/lmdb-opener.d.ts +17 -0
- package/types/db/core/lmdb-opener.d.ts.map +1 -0
- package/types/db/core/lmdber.d.ts +60 -383
- package/types/db/core/lmdber.d.ts.map +1 -1
- package/types/db/core/memstore.d.ts +129 -0
- package/types/db/core/memstore.d.ts.map +1 -0
- package/types/db/core/path-manager.d.ts +22 -45
- package/types/db/core/path-manager.d.ts.map +1 -1
- package/types/db/core/store-owner.d.ts +59 -0
- package/types/db/core/store-owner.d.ts.map +1 -0
- package/types/db/core/webdber.d.ts +127 -0
- package/types/db/core/webdber.d.ts.map +1 -0
- package/types/db/escrowing.d.ts +3 -3
- package/types/db/escrowing.d.ts.map +1 -1
- package/types/db/exchange/exchange-nests.d.ts.map +1 -1
- package/types/db/indexeddb.d.ts +37 -0
- package/types/db/indexeddb.d.ts.map +1 -0
- package/types/db/keeping.d.ts +14 -25
- package/types/db/keeping.d.ts.map +1 -1
- package/types/db/koming.d.ts +7 -8
- package/types/db/koming.d.ts.map +1 -1
- package/types/db/lmdb-stores.d.ts +45 -0
- package/types/db/lmdb-stores.d.ts.map +1 -0
- package/types/db/lmdb.d.ts +7 -0
- package/types/db/lmdb.d.ts.map +1 -0
- package/types/db/mailbox/mailboxing.d.ts +7 -21
- package/types/db/mailbox/mailboxing.d.ts.map +1 -1
- package/types/db/noting.d.ts +7 -12
- package/types/db/noting.d.ts.map +1 -1
- package/types/db/reger.d.ts +7 -11
- package/types/db/reger.d.ts.map +1 -1
- package/types/db/replay/witness-replay.d.ts +0 -2
- package/types/db/replay/witness-replay.d.ts.map +1 -1
- package/types/db/store-lock.d.ts +72 -0
- package/types/db/store-lock.d.ts.map +1 -0
- package/types/db/subing.d.ts +24 -25
- package/types/db/subing.d.ts.map +1 -1
- package/types/npm/db-indexeddb.d.ts +4 -0
- package/types/npm/db-indexeddb.d.ts.map +1 -0
- package/types/npm/db-lmdb.d.ts +4 -0
- package/types/npm/db-lmdb.d.ts.map +1 -0
- package/types/npm/runtime-node.d.ts +4 -0
- package/types/npm/runtime-node.d.ts.map +1 -0
- package/types/npm/runtime-web.d.ts +4 -0
- package/types/npm/runtime-web.d.ts.map +1 -0
- package/types/runtime/index.d.ts +48 -14
- package/types/runtime/index.d.ts.map +1 -1
- package/types/runtime/node.d.ts +15 -0
- package/types/runtime/node.d.ts.map +1 -0
- package/types/runtime/web/output-barrier.d.ts +30 -0
- package/types/runtime/web/output-barrier.d.ts.map +1 -0
- package/types/runtime/web/persistent-storage.d.ts +36 -0
- package/types/runtime/web/persistent-storage.d.ts.map +1 -0
- package/types/runtime/web.d.ts +11 -0
- package/types/runtime/web.d.ts.map +1 -0
- package/types/vdr/tel-publication.d.ts +6 -0
- package/types/vdr/tel-publication.d.ts.map +1 -1
- package/types/version.d.ts +2 -2
- package/esm/keri/npm/src/acdc/relating.js +0 -59
- package/esm/keri/npm/src/cli/common/tel-completion.js +0 -24
- package/esm/keri/npm/src/db/baser-defaults.js +0 -11
- package/types/acdc/relating.d.ts +0 -21
- package/types/acdc/relating.d.ts.map +0 -1
- package/types/cli/common/tel-completion.d.ts +0 -8
- package/types/cli/common/tel-completion.d.ts.map +0 -1
- package/types/db/baser-defaults.d.ts +0 -5
- package/types/db/baser-defaults.d.ts.map +0 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure read of the Grants a disclosee holds pending until it fetches their registry proofs.
|
|
3
|
+
*
|
|
4
|
+
* A presentation Grant reaches the disclosee as a pending exchange: it is authenticated and stored, but
|
|
5
|
+
* stays unfinished until `requestUnblind` completes the registry proofs behind it. This lists the pending
|
|
6
|
+
* v2 Grants addressed to local identifiers whose deadline has not passed. An issuance Grant waiting for the
|
|
7
|
+
* holder's exchange consent is pending in the same table; `pendingIssuanceGrants` names those, and a caller
|
|
8
|
+
* that wants presentations only removes them.
|
|
9
|
+
*/
|
|
10
|
+
import { SerderACDC } from "cesr-ts";
|
|
11
|
+
import { ValidationError } from "../../core/errors.js";
|
|
12
|
+
import { unblindingStatus } from "./unblinding-workflow.js";
|
|
13
|
+
/**
|
|
14
|
+
* The pending v2 Grants addressed to a local identifier (to `hab` when given) that are inside their deadline.
|
|
15
|
+
* Mutates nothing.
|
|
16
|
+
*/
|
|
17
|
+
export function pendingPresentations(ops, { hab } = {}) {
|
|
18
|
+
const { deps } = ops, found = [];
|
|
19
|
+
for (const [[grant], serder] of [...deps.hby.db.epse.getTopItemIter()]) {
|
|
20
|
+
const disclosee = serder.sad?.ri;
|
|
21
|
+
if (serder.route !== "/ipex/grant" || serder.pvrsn.major < 2 || typeof disclosee !== "string")
|
|
22
|
+
continue;
|
|
23
|
+
if (!deps.hby.habs.has(disclosee) || (hab && hab.pre !== disclosee))
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
const status = unblindingStatus(ops, grant);
|
|
27
|
+
if (status.state !== "active" && status.state !== "interrupted")
|
|
28
|
+
continue;
|
|
29
|
+
const body = deps.exc.retainedInput(grant)?.nests?.[0]?.body;
|
|
30
|
+
found.push({
|
|
31
|
+
grant,
|
|
32
|
+
disclosee,
|
|
33
|
+
presenter: serder.pre,
|
|
34
|
+
credential: body instanceof SerderACDC ? body.said ?? undefined : undefined,
|
|
35
|
+
deadline: deps.exc.exchangeDeadline(serder),
|
|
36
|
+
status,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
// Not a Grant this runtime can unblind (no deadline): it is not pending here.
|
|
41
|
+
if (!(error instanceof ValidationError))
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return found;
|
|
46
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact public Grant files for a group presentation: the runtime's half of the file hand-off.
|
|
3
|
+
*
|
|
4
|
+
* A group presenter freezes one selected public view as an exact Grant file, a member appends its signature to
|
|
5
|
+
* the same file ({@link preparePresentationFile}), and the completed file is imported once the sender threshold
|
|
6
|
+
* is met ({@link resumePresentationFile}); the elected lead then delivers it ({@link deliverPreparedGrant} in
|
|
7
|
+
* `presenting.ts`). The file is only the transport between members: every check of what a file may change (the
|
|
8
|
+
* exact body and nested evidence, the original deadline, the issuer authorization of every selected registry
|
|
9
|
+
* node) is here, not in the command that reads and writes the file.
|
|
10
|
+
*/
|
|
11
|
+
import { bytesEqual, collectPayload, concatBytes, Counter, framePayload, parseAttachmentGroup, parseBytes, SerderKERI, Vrsn_2_0, } from "cesr-ts";
|
|
12
|
+
import { call } from "effection";
|
|
13
|
+
import { grantTransactionId } from "../../acdc/dhking.js";
|
|
14
|
+
import { ValidationError } from "../../core/errors.js";
|
|
15
|
+
import { messageAttachmentGroups } from "../../core/protocol-serialization.js";
|
|
16
|
+
import { timestampMicros } from "../../time/mod.js";
|
|
17
|
+
import { isLocalGroupHab } from "../multisig/group-members.js";
|
|
18
|
+
import { envelopeFromFrame } from "../protocol/parsering.js";
|
|
19
|
+
import { exchangeWire, IpexDiscloser } from "./ipex-discloser.js";
|
|
20
|
+
/** Borrow the actual local signer and enabled KRAM; KRAM policy owns the preparation lifetime. */
|
|
21
|
+
function discloserOf(deps, hab) {
|
|
22
|
+
if (deps.hby.habs.get(hab.pre) !== hab || !deps.protocol.kvy.kramer) {
|
|
23
|
+
throw new ValidationError("Prepared presentation requires its local habitat, registry and enabled KRAM");
|
|
24
|
+
}
|
|
25
|
+
return new IpexDiscloser(deps.hby, deps.rgy.store, deps.exc, deps.receiptor, undefined, deps.views);
|
|
26
|
+
}
|
|
27
|
+
/** Keep the original v2 IPEX clock; no file can recreate a missing or terminated preparation. */
|
|
28
|
+
function deadline(deps, said, expected) {
|
|
29
|
+
const selected = deps.exc.retainedInput(said)?.serder;
|
|
30
|
+
const date = selected && deps.exc.exchangeDeadline(selected);
|
|
31
|
+
if (!date || deps.hby.db.erpy.get([said]) || expected !== undefined && date !== expected) {
|
|
32
|
+
throw new ValidationError("Prepared Grant is unavailable, terminated or its original deadline changed");
|
|
33
|
+
}
|
|
34
|
+
const expiry = timestampMicros(date);
|
|
35
|
+
if (expiry === null)
|
|
36
|
+
throw new Error("Corrupt prepared presentation deadline");
|
|
37
|
+
if (BigInt(deps.clock.now()) * 1000n >= expiry) {
|
|
38
|
+
throw new ValidationError("Original prepared presentation deadline expired");
|
|
39
|
+
}
|
|
40
|
+
return date;
|
|
41
|
+
}
|
|
42
|
+
/** Serialize exact existing frames; signatures never authorize a change to nested public evidence. */
|
|
43
|
+
function* wire(frame) {
|
|
44
|
+
return yield* call(() => collectPayload(framePayload(frame)));
|
|
45
|
+
}
|
|
46
|
+
/** Compare complete nested bytes, including every original proof family and order. */
|
|
47
|
+
function* sameNodes(left, right) {
|
|
48
|
+
if (left.nests?.length !== right.nests?.length)
|
|
49
|
+
return false;
|
|
50
|
+
for (let i = 0; i < (left.nests?.length ?? 0); i++) {
|
|
51
|
+
if (!bytesEqual(yield* wire(left.nests[i]), yield* wire(right.nests[i])))
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
/** Project individual factors rather than grouping serialization, allowing only authentication additions. */
|
|
57
|
+
function factors(frame) {
|
|
58
|
+
const proof = envelopeFromFrame(frame);
|
|
59
|
+
return new Set([
|
|
60
|
+
...proof.tsgs.flatMap(group => group.sigers.map(sig => JSON.stringify(["tsg", group.pre, group.sn.toString(), group.said, sig.qb64]))),
|
|
61
|
+
...proof.cigars.map(cigar => JSON.stringify(["cigar", cigar.verfer?.qb64, cigar.qb64])),
|
|
62
|
+
...proof.ssts.map(seal => JSON.stringify(["seal", seal.i.qb64, seal.s.num.toString(), seal.d.qb64])),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
/** Feed exact signed factors through the ordinary exchange owner; nested authority remains independent. */
|
|
66
|
+
function input(frame) {
|
|
67
|
+
const proof = envelopeFromFrame(frame);
|
|
68
|
+
return {
|
|
69
|
+
serder: frame.body,
|
|
70
|
+
tsgs: proof.tsgs,
|
|
71
|
+
cigars: proof.cigars,
|
|
72
|
+
sourceSeals: proof.ssts,
|
|
73
|
+
nests: frame.nests,
|
|
74
|
+
gvrsn: Vrsn_2_0,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Reconstruct the authenticated original before importing any completed file. */
|
|
78
|
+
function retained(deps, said) {
|
|
79
|
+
const saved = deps.exc.retainedInput(said);
|
|
80
|
+
if (!saved)
|
|
81
|
+
throw new ValidationError("Resume requires the original locally prepared sender threshold");
|
|
82
|
+
const frame = {
|
|
83
|
+
body: saved.serder,
|
|
84
|
+
attachments: messageAttachmentGroups({ tsgs: saved.tsgs, cigars: saved.cigars, sourceSeals: saved.sourceSeals }, Vrsn_2_0).map(group => parseAttachmentGroup(group.raw, Vrsn_2_0, "txt").group),
|
|
85
|
+
gvrsn: Vrsn_2_0,
|
|
86
|
+
nests: [...saved.nests ?? []],
|
|
87
|
+
};
|
|
88
|
+
return frame;
|
|
89
|
+
}
|
|
90
|
+
/** Require issuer authority for every selected registry node, including retryably unknown current openings. */
|
|
91
|
+
function requireScope(deps, frame) {
|
|
92
|
+
const body = frame.body, xid = grantTransactionId(body);
|
|
93
|
+
const context = deps.exc.presentationContext(body.said, {
|
|
94
|
+
xid,
|
|
95
|
+
sender: body.pre,
|
|
96
|
+
recipient: body.sad.ri,
|
|
97
|
+
});
|
|
98
|
+
const expected = new Map();
|
|
99
|
+
for (const node of frame.nests ?? []) {
|
|
100
|
+
const credential = node.body;
|
|
101
|
+
if (credential.regid) {
|
|
102
|
+
const nodes = expected.get(credential.regid) ?? new Set();
|
|
103
|
+
nodes.add(credential.said);
|
|
104
|
+
expected.set(credential.regid, nodes);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!expected.size || !context || context.registries.size !== expected.size
|
|
108
|
+
|| [...expected].some(([regid, nodes]) => context.registries.get(regid)?.length !== nodes.size
|
|
109
|
+
|| context.registries.get(regid).some(said => !nodes.has(said)))) {
|
|
110
|
+
throw new ValidationError("Exact Grant lacks complete issuer authorization for every selected registry node");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Freeze one selected public view; a group member may append its signature to the same exact proposal file. */
|
|
114
|
+
export function* preparePresentationFile(deps, hab, selection, options, proposal) {
|
|
115
|
+
const owner = discloserOf(deps, hab);
|
|
116
|
+
if ((options.gvrsn ?? Vrsn_2_0).major !== 2)
|
|
117
|
+
throw new ValidationError("Prepared presentation requires genus 2");
|
|
118
|
+
if (selection.refresh || selection.derive || selection.openings?.length || options.anchor) {
|
|
119
|
+
throw new ValidationError("Exact preparation preserves the selected view; refresh and anchored presentation use their existing commands");
|
|
120
|
+
}
|
|
121
|
+
if (proposal && !isLocalGroupHab(deps.hby, hab)) {
|
|
122
|
+
throw new ValidationError("A sender contribution requires a local group member");
|
|
123
|
+
}
|
|
124
|
+
const original = proposal ? owner.inspectGrantFile(proposal).frame : undefined;
|
|
125
|
+
const body = original?.body;
|
|
126
|
+
const previous = body && deps.exc.exchangeDeadline(body) ? deadline(deps, body.said) : undefined;
|
|
127
|
+
const prepared = yield* owner.prepareGrantFileBody(hab.pre, selection, {
|
|
128
|
+
...options,
|
|
129
|
+
...(body ? { date: body.stamp, kind: body.kind } : {}),
|
|
130
|
+
});
|
|
131
|
+
const exn = body?.ilk === "xip"
|
|
132
|
+
? new SerderKERI({ sad: { ...prepared.exn.sad, u: body.sad.u }, kind: body.kind, makify: true })
|
|
133
|
+
: prepared.exn;
|
|
134
|
+
const unsigned = parseBytes(concatBytes(Counter.makeGVC(Vrsn_2_0), exn.raw, Counter.enclose({ qb64: prepared.nests, version: Vrsn_2_0 })))[0];
|
|
135
|
+
if (original && (!bytesEqual(exn.raw, original.body.raw) || !(yield* sameNodes(unsigned, original)))) {
|
|
136
|
+
throw new ValidationError("Group contribution differs from the selected view, exact Grant or parties");
|
|
137
|
+
}
|
|
138
|
+
if (previous)
|
|
139
|
+
deadline(deps, exn.said, previous);
|
|
140
|
+
const candidate = parseBytes(exchangeWire(hab, exn, prepared.nests))[0];
|
|
141
|
+
if (original)
|
|
142
|
+
candidate.attachments = [...original.attachments, ...candidate.attachments];
|
|
143
|
+
const raw = yield* wire(candidate), checked = owner.inspectGrantFile(raw);
|
|
144
|
+
if (previous)
|
|
145
|
+
deadline(deps, exn.said, previous);
|
|
146
|
+
if (previous) {
|
|
147
|
+
const decision = yield* deps.exc.acceptPreparedGrantContribution(input(candidate));
|
|
148
|
+
if (decision.kind === "reject")
|
|
149
|
+
throw new ValidationError(decision.reason);
|
|
150
|
+
}
|
|
151
|
+
else if (checked.completeSigners.includes(hab.pre)) {
|
|
152
|
+
yield* deps.reactor.processBytes(raw, { local: true });
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Keep partial sender proof in ordinary escrow without granting accepted KRAM authority.
|
|
156
|
+
const decision = yield* deps.exc.processEvent(input(candidate));
|
|
157
|
+
if (decision.kind === "reject")
|
|
158
|
+
throw new ValidationError(decision.reason);
|
|
159
|
+
}
|
|
160
|
+
// A partial group proposal has no accepted lifetime and grants no auxiliary authority.
|
|
161
|
+
const frozen = deps.exc.exchangeDeadline(exn) ? deadline(deps, exn.said, previous) : null;
|
|
162
|
+
const saved = deps.hby.db.exns.get([exn.said]) ?? deps.hby.db.epse.get([exn.said]);
|
|
163
|
+
if (!saved || !bytesEqual(saved.raw, exn.raw)) {
|
|
164
|
+
throw new ValidationError("v2 IPEX preparation did not retain the exact Grant");
|
|
165
|
+
}
|
|
166
|
+
return { grant: exn.said, wire: raw, prepared: checked.completeSigners.includes(hab.pre), deadline: frozen };
|
|
167
|
+
}
|
|
168
|
+
/** Import only additions to an existing sender-authenticated preparation; missing issuer consent cannot be recreated. */
|
|
169
|
+
export function* resumePresentationFile(deps, hab, said, raw) {
|
|
170
|
+
const owner = discloserOf(deps, hab), frozen = deadline(deps, said), original = retained(deps, said);
|
|
171
|
+
if (original.body.pre !== hab.pre) {
|
|
172
|
+
throw new ValidationError("Resume selects the original local discloser");
|
|
173
|
+
}
|
|
174
|
+
const candidate = owner.inspectGrantFile(raw, {
|
|
175
|
+
said,
|
|
176
|
+
sender: hab.pre,
|
|
177
|
+
recipient: original.body.sad.ri,
|
|
178
|
+
});
|
|
179
|
+
if (candidate.partialSigners.length || !candidate.completeSigners.includes(hab.pre)
|
|
180
|
+
|| !bytesEqual(candidate.frame.body.raw, original.body.raw) || !(yield* sameNodes(candidate.frame, original))) {
|
|
181
|
+
throw new ValidationError("Resume requires complete authentication on the exact original Grant and nested evidence");
|
|
182
|
+
}
|
|
183
|
+
const added = factors(candidate.frame);
|
|
184
|
+
if ([...factors(original)].some(factor => !added.has(factor))) {
|
|
185
|
+
throw new ValidationError("Resume cannot remove original authentication");
|
|
186
|
+
}
|
|
187
|
+
deadline(deps, said, frozen);
|
|
188
|
+
const decision = yield* deps.exc.acceptPreparedGrantContribution(input(candidate.frame));
|
|
189
|
+
if (decision.kind === "reject")
|
|
190
|
+
throw new ValidationError(decision.reason);
|
|
191
|
+
deadline(deps, said, frozen);
|
|
192
|
+
requireScope(deps, candidate.frame);
|
|
193
|
+
const nodes = concatBytes(Counter.makeGVC(Vrsn_2_0), ...yield* call(() => Promise.all(candidate.frame.nests.map((node) => collectPayload(framePayload(node))))));
|
|
194
|
+
return {
|
|
195
|
+
grant: said,
|
|
196
|
+
wire: raw.slice(),
|
|
197
|
+
deadline: frozen,
|
|
198
|
+
delivery: concatBytes(owner.proofSupport(nodes, hab), raw),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime-owned operations for single-signature v2 IPEX presentation.
|
|
3
|
+
*
|
|
4
|
+
* `present` is the user's one explicit consent: it selects the credential view, signs the Offer, Grant,
|
|
5
|
+
* Apply, Agree or Spurn (a Grant may also anchor its presentation proof under that same consent), takes
|
|
6
|
+
* the signed exchange into local authenticated intake and queues it. It returns after local commit and
|
|
7
|
+
* never waits for the peer. `PresentationOperations.processOnce` is the only worker: it delivers the
|
|
8
|
+
* already signed bytes, retries a failed delivery with a doubling delay until the exchange's deadline
|
|
9
|
+
* and ends the operation at the Grant's original exchange deadline. It never signs.
|
|
10
|
+
*
|
|
11
|
+
* There is no operation store. The signed exchange is itself durable (the accepted exchange and its
|
|
12
|
+
* signatures), and `resendPresentation` rebuilds its wire from those stored factors, signing nothing, so
|
|
13
|
+
* a process that ended before or during delivery can deliver again on the user's explicit request. Nothing
|
|
14
|
+
* is sent after a restart on its own.
|
|
15
|
+
*
|
|
16
|
+
* Status is the live table plus what the stores prove. Delivery itself leaves no protocol record, so
|
|
17
|
+
* only the peer's stored answer proves it:
|
|
18
|
+
*
|
|
19
|
+
* | stores prove | status |
|
|
20
|
+
* | --------------------------------------------------------- | -------------------------------------------- |
|
|
21
|
+
* | the peer's answer is stored (`erpy`) | `done`, with the `response` |
|
|
22
|
+
* | signed exchange accepted, deadline passed, no answer | `expired` |
|
|
23
|
+
* | signed exchange accepted, no answer, not live | `interrupted`: `resendPresentation` delivers |
|
|
24
|
+
*
|
|
25
|
+
* Lost on reload, by design: the delivery attempts and the last transport failure, the `abandoned` and
|
|
26
|
+
* `failed` end states with their reasons, the delivery destinations, and the fact of a delivery nobody
|
|
27
|
+
* answered (it reads `done` in the process that delivered it and `interrupted` after a reload; sending it
|
|
28
|
+
* again is harmless, the peer deduplicates by SAID).
|
|
29
|
+
*
|
|
30
|
+
* Workflow-contract shape (`app/runtime/workflow-contract.ts`): `present` returns after local commit,
|
|
31
|
+
* `presentationStatus` is a pure read, `waitForPresentation` only observes and returns a `WaitResult`, and
|
|
32
|
+
* `abandonPresentation` is local. A host that wants only the signed bytes (a file, a QR code) uses
|
|
33
|
+
* `preparePresentation`, which commits locally and queues nothing.
|
|
34
|
+
*
|
|
35
|
+
* Group identifiers are refused here: a group presents through {@link proposeGroupPresentation}, which hands the
|
|
36
|
+
* frozen Grant to the group IPEX owner (`group-ipex.ts`) for member approval.
|
|
37
|
+
*/
|
|
38
|
+
import { collectPayload, concatBytes, Counter, framePayload, parseBytes, Vrsn_2_0, } from "cesr-ts";
|
|
39
|
+
import { action, call, race } from "effection";
|
|
40
|
+
import { RegistryCustody } from "../../acdc/custody.js";
|
|
41
|
+
import { ValidationError } from "../../core/errors.js";
|
|
42
|
+
import { timestampMicros } from "../../time/mod.js";
|
|
43
|
+
import { registryEventRef } from "../credentials/registry-settling.js";
|
|
44
|
+
import { isLocalGroupHab, localGroupMember } from "../multisig/group-members.js";
|
|
45
|
+
import { proposeRegistryEvent } from "../multisig/proposing.js";
|
|
46
|
+
import { DeliveryOutbox } from "../runtime/delivery-outbox.js";
|
|
47
|
+
import { observeUntil, waitOnClock } from "../runtime/workflow-contract.js";
|
|
48
|
+
import { proposeGroupIpex, proposeGroupIpexAfter as groupIpexAfter, } from "./group-ipex.js";
|
|
49
|
+
import { IpexDiscloser, storedExchangeWire, } from "./ipex-discloser.js";
|
|
50
|
+
import { prepareAcdcV2GroupIpex } from "./ipex-grouping.js";
|
|
51
|
+
/** How long delivery failures may last on an exchange with no deadline (an Apply, an Agree) before it reads `failed`. */
|
|
52
|
+
export const PRESENTATION_RETRY_BOUND_MS = 600_000;
|
|
53
|
+
const EXPIRED = "The presentation reached its original exchange deadline";
|
|
54
|
+
const PENDING = "ACDC v2 exchange remains pending authenticated intake.";
|
|
55
|
+
function iso(ms) {
|
|
56
|
+
return new Date(ms).toISOString();
|
|
57
|
+
}
|
|
58
|
+
function message(error) {
|
|
59
|
+
return error instanceof Error ? error.message : String(error);
|
|
60
|
+
}
|
|
61
|
+
/** Whether the exchange's deadline has passed; an exchange without one never lapses. */
|
|
62
|
+
function lapsed(clock, deadline) {
|
|
63
|
+
const expiry = timestampMicros(deadline);
|
|
64
|
+
return expiry !== null && BigInt(clock.now()) * 1000n >= expiry;
|
|
65
|
+
}
|
|
66
|
+
/** The live deliveries table and its driver. One per host runtime; every identifier may present through it. */
|
|
67
|
+
export class PresentationOperations {
|
|
68
|
+
constructor(deps) {
|
|
69
|
+
Object.defineProperty(this, "deps", {
|
|
70
|
+
enumerable: true,
|
|
71
|
+
configurable: true,
|
|
72
|
+
writable: true,
|
|
73
|
+
value: deps
|
|
74
|
+
});
|
|
75
|
+
/** Deliveries live in this process. Internal to this module's functions. */
|
|
76
|
+
Object.defineProperty(this, "live", {
|
|
77
|
+
enumerable: true,
|
|
78
|
+
configurable: true,
|
|
79
|
+
writable: true,
|
|
80
|
+
value: new Map()
|
|
81
|
+
});
|
|
82
|
+
/** Presentations that delivered or ended in this process; not durable, see the module doc. */
|
|
83
|
+
Object.defineProperty(this, "settled", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
writable: true,
|
|
87
|
+
value: new Map()
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** Whether a delivery is live. */
|
|
91
|
+
active() {
|
|
92
|
+
return this.live.size > 0;
|
|
93
|
+
}
|
|
94
|
+
/** Advance every live delivery by one pass. */
|
|
95
|
+
*processOnce() {
|
|
96
|
+
const { deps } = this;
|
|
97
|
+
for (const op of [...this.live.values()]) {
|
|
98
|
+
if (op.busy || !this.live.has(op.said))
|
|
99
|
+
continue;
|
|
100
|
+
op.busy = true;
|
|
101
|
+
try {
|
|
102
|
+
const left = op.expires === null ? null : op.expires - BigInt(deps.clock.now()) * 1000n;
|
|
103
|
+
if (left !== null && left <= 0n)
|
|
104
|
+
this.end(op, "expired", EXPIRED);
|
|
105
|
+
else if ((yield* race([this.deliver(op), this.timer(left)])) === "expired")
|
|
106
|
+
this.end(op, "expired", EXPIRED);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
op.busy = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** End a live delivery: drop it, remember why until the process ends, tell the sink. */
|
|
114
|
+
end(op, state, reason) {
|
|
115
|
+
this.live.delete(op.said);
|
|
116
|
+
this.settled.set(op.said, { verb: op.verb, state, reason });
|
|
117
|
+
this.deps.changes?.push({ kind: "presentation", id: op.said });
|
|
118
|
+
}
|
|
119
|
+
/** Resolves only when the deadline passes; never resolves for an exchange without one. */
|
|
120
|
+
*timer(left) {
|
|
121
|
+
if (left === null)
|
|
122
|
+
return yield* action(() => () => { });
|
|
123
|
+
yield* waitOnClock(this.deps.clock, Number(left) / 1000);
|
|
124
|
+
return "expired";
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* One attempt: a failure keeps the bytes and is retried after a doubling delay until the exchange's deadline,
|
|
128
|
+
* or, for an exchange with none, until failures have lasted {@link PRESENTATION_RETRY_BOUND_MS}.
|
|
129
|
+
*/
|
|
130
|
+
*deliver(op) {
|
|
131
|
+
const { deps } = this;
|
|
132
|
+
try {
|
|
133
|
+
const done = yield* op.outbox.drain(deps.delivery, deps.clock, op.expires === null ? PRESENTATION_RETRY_BOUND_MS : undefined);
|
|
134
|
+
if (!done) {
|
|
135
|
+
deps.changes?.push({ kind: "presentation", id: op.said });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
this.end(op, "failed", message(error));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.live.delete(op.said);
|
|
144
|
+
this.settled.set(op.said, { verb: op.verb, state: "done", deliveries: op.outbox.delivered });
|
|
145
|
+
deps.changes?.push({ kind: "presentation", id: op.said });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const RESEND = "Delivery is not recorded across a restart and no answer is stored; resendPresentation delivers it again";
|
|
149
|
+
/** The discloser for one sender; derivation needs custody over the sender's own Keeper root. */
|
|
150
|
+
function discloserFor(deps, hab, derive) {
|
|
151
|
+
let custody;
|
|
152
|
+
if (derive) {
|
|
153
|
+
if (!deps.derived)
|
|
154
|
+
throw new ValidationError("Derived disclosure requires the embedder's derivation store.");
|
|
155
|
+
custody = new RegistryCustody({ hby: deps.hby, hab, registry: deps.rgy.store, store: deps.derived });
|
|
156
|
+
}
|
|
157
|
+
return new IpexDiscloser(deps.hby, deps.rgy.store, deps.exc, deps.receiptor, custody, deps.views);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Sign the selected message and take it into local authenticated intake, without recording an operation or
|
|
161
|
+
* delivering. This is the whole consent: the returned bytes are final.
|
|
162
|
+
*
|
|
163
|
+
* @throws ValidationError for a group identifier, an unknown presentation registry, a selection the discloser
|
|
164
|
+
* refuses, or an exchange that does not reach authenticated intake.
|
|
165
|
+
*/
|
|
166
|
+
export function* preparePresentation(deps, input) {
|
|
167
|
+
const { hab } = input;
|
|
168
|
+
let presentation;
|
|
169
|
+
if (input.verb === "grant" && input.options.presentationRegistry) {
|
|
170
|
+
presentation = deps.rgy.registryByName(input.options.presentationRegistry);
|
|
171
|
+
if (!presentation)
|
|
172
|
+
throw new ValidationError("Unknown presentation registry.");
|
|
173
|
+
}
|
|
174
|
+
const discloser = discloserFor(deps, hab, "selection" in input ? input.selection.derive : undefined);
|
|
175
|
+
const sender = hab.pre;
|
|
176
|
+
let prepared;
|
|
177
|
+
switch (input.verb) {
|
|
178
|
+
case "apply":
|
|
179
|
+
prepared = yield* discloser.prepareApply(sender, input.options);
|
|
180
|
+
break;
|
|
181
|
+
case "agree":
|
|
182
|
+
case "spurn":
|
|
183
|
+
prepared = yield* discloser.prepareReply(sender, input.verb, input.prior, input.message ?? "", input.recipient, input.auths);
|
|
184
|
+
break;
|
|
185
|
+
case "offer":
|
|
186
|
+
prepared = yield* discloser.prepareOffer(sender, input.selection, input.options);
|
|
187
|
+
break;
|
|
188
|
+
case "grant":
|
|
189
|
+
prepared = yield* discloser.prepareGrant(sender, input.selection, {
|
|
190
|
+
...input.options,
|
|
191
|
+
presentation: presentation ?? undefined,
|
|
192
|
+
});
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
const wire = concatBytes(discloser.kel(hab), prepared.support, prepared.wire);
|
|
196
|
+
yield* deps.reactor.processBytes(wire, { local: true });
|
|
197
|
+
yield* deps.protocol.processEscrowsOnce();
|
|
198
|
+
if (!deps.exc.complete(prepared.exn.said))
|
|
199
|
+
throw new ValidationError(PENDING);
|
|
200
|
+
return { exn: prepared.exn, wire, recipient: prepared.exn.sad.ri };
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* A group's consent to present an accepted Grant or credential view: freezes the Grant body once (selection and
|
|
204
|
+
* authorization) and proposes it as a group-authored message, so the other members list and approve it with
|
|
205
|
+
* `approveGroupIpex` and the elected lead delivers the completed Grant. Returns after local commit.
|
|
206
|
+
*
|
|
207
|
+
* With `options.presentationRegistry` the Grant carries a presented-state proof: this member also proposes the
|
|
208
|
+
* registry update that anchors it (`proposeRegistryEvent`; the other members approve that proposal with
|
|
209
|
+
* `approveGroupProposal`), and the owner signs this member's contribution to the Grant once the group has accepted
|
|
210
|
+
* the update, under this same consent.
|
|
211
|
+
*
|
|
212
|
+
* @throws ValidationError for an identifier that is not a local group, an unknown presentation registry, a
|
|
213
|
+
* selection the discloser refuses, or a message awaiting authenticating dependencies.
|
|
214
|
+
*/
|
|
215
|
+
export function* proposeGroupPresentation(deps, groupIpex, { hab, selection, options, deliver, counsel }) {
|
|
216
|
+
const { presentationRegistry, ...body } = options;
|
|
217
|
+
const gvrsn = body.gvrsn ?? undefined;
|
|
218
|
+
const discloser = discloserFor(deps, hab, selection.derive);
|
|
219
|
+
let prepared = yield* discloser.prepareGrantBody(hab.pre, selection, body);
|
|
220
|
+
if (!presentationRegistry) {
|
|
221
|
+
return yield* proposeGroupIpex(groupIpex, { hab, exn: prepared.exn, nests: prepared.nests, gvrsn, deliver });
|
|
222
|
+
}
|
|
223
|
+
const reg = deps.rgy.registryByName(presentationRegistry);
|
|
224
|
+
if (!reg)
|
|
225
|
+
throw new ValidationError("Unknown presentation registry.");
|
|
226
|
+
const node = parseBytes(prepared.raw)[0].body;
|
|
227
|
+
if (reg.hab.pre !== hab.pre || node.issuee !== hab.pre || node.sad.a.rd !== reg.regk) {
|
|
228
|
+
throw new ValidationError("Presentation registry must match the selected disclosed local Issuee declaration.");
|
|
229
|
+
}
|
|
230
|
+
const proposals = groupIpex.deps.registry;
|
|
231
|
+
if (!proposals)
|
|
232
|
+
throw new ValidationError("This owner was composed without group registry collaborators");
|
|
233
|
+
// The Grant SAID is frozen before the update is anchored; only its nested proof is extended afterwards.
|
|
234
|
+
const [proof, update] = reg.present(prepared.exn, "presented", { stamp: body.stamp });
|
|
235
|
+
const proposed = yield* proposeRegistryEvent(proposals, hab, update, proof, counsel);
|
|
236
|
+
const exn = prepared.exn;
|
|
237
|
+
return groupIpexAfter(groupIpex, {
|
|
238
|
+
hab,
|
|
239
|
+
exn,
|
|
240
|
+
gvrsn,
|
|
241
|
+
deliver,
|
|
242
|
+
prerequisite: {
|
|
243
|
+
anchor: registryEventRef(update, proposed.event),
|
|
244
|
+
*proceed() {
|
|
245
|
+
const seal = deps.rgy.store.anchor(update.said);
|
|
246
|
+
if (!seal)
|
|
247
|
+
throw new ValidationError("The presentation update is accepted but its anchor is unavailable");
|
|
248
|
+
prepared = yield* discloser.attachPresentationProof(prepared, proof, { s: seal[0], d: seal[1] });
|
|
249
|
+
const candidate = concatBytes(Counter.makeGVC(gvrsn ?? Vrsn_2_0), prepared.exn.raw, Counter.enclose({ qb64: prepared.nests, version: gvrsn ?? Vrsn_2_0 }));
|
|
250
|
+
const own = yield* prepareAcdcV2GroupIpex(deps.hby, groupIpex.deps.protocol, hab, candidate);
|
|
251
|
+
if (!own)
|
|
252
|
+
throw new ValidationError("ACDC v2 group disclosure awaits authenticating dependencies.");
|
|
253
|
+
return own;
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Deliver a group's completed prepared Grant ({@link resumePresentationFile}): queues the delivery bytes for
|
|
260
|
+
* `processOnce` when the local member is the elected lead, with the retry and deadline of any presentation. Signs
|
|
261
|
+
* nothing. Returns null for a member that is not the lead.
|
|
262
|
+
*/
|
|
263
|
+
export function deliverPreparedGrant(ops, { hab, said, delivery }) {
|
|
264
|
+
const { deps } = ops, serder = deps.exc.retainedInput(said)?.serder;
|
|
265
|
+
if (!serder || serder.pre !== hab.pre)
|
|
266
|
+
throw new ValidationError("Delivery selects the group's own prepared Grant");
|
|
267
|
+
if (!deps.exc.lead(hab, said, { pendingPresentation: true }))
|
|
268
|
+
return null;
|
|
269
|
+
const recipient = String(serder.sad.ri), deadline = deps.exc.exchangeDeadline(serder) ?? undefined;
|
|
270
|
+
const src = isLocalGroupHab(deps.hby, hab) ? localGroupMember(deps.hby, hab.pre).pre : hab.pre;
|
|
271
|
+
queue(ops, { said, verb: "grant", hab, src, recipient, wire: delivery, deadline });
|
|
272
|
+
deps.changes?.push({ kind: "presentation", id: said });
|
|
273
|
+
return { said, recipient, wire: delivery };
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* The user's consent to present: signs and takes the message into local intake ({@link preparePresentation}),
|
|
277
|
+
* records the operation and queues the signed bytes for `processOnce` to deliver. Returns after local commit.
|
|
278
|
+
*/
|
|
279
|
+
export function* present(ops, input) {
|
|
280
|
+
const { deps } = ops;
|
|
281
|
+
const { exn, wire, recipient } = yield* preparePresentation(deps, input);
|
|
282
|
+
const said = exn.said, deadline = deps.exc.exchangeDeadline(exn) ?? undefined;
|
|
283
|
+
queue(ops, { said, verb: input.verb, hab: input.hab, recipient, wire, deadline });
|
|
284
|
+
deps.changes?.push({ kind: "presentation", id: said });
|
|
285
|
+
return { said, recipient, wire };
|
|
286
|
+
}
|
|
287
|
+
function queue(ops, op) {
|
|
288
|
+
const outbox = new DeliveryOutbox(ops.deps.retry);
|
|
289
|
+
outbox.enqueue({ src: op.src ?? op.hab.pre, dest: op.recipient, msg: op.wire });
|
|
290
|
+
ops.settled.delete(op.said);
|
|
291
|
+
ops.live.set(op.said, { ...op, expires: timestampMicros(op.deadline), outbox, busy: false });
|
|
292
|
+
}
|
|
293
|
+
/** The signed exchange of a local sender, with the verb its route names. */
|
|
294
|
+
function signed(deps, said) {
|
|
295
|
+
const serder = deps.hby.db.exns.get([said]), hab = serder?.pre ? deps.hby.habs.get(serder.pre) : undefined;
|
|
296
|
+
const verb = serder?.route?.startsWith("/ipex/") ? serder.route.slice("/ipex/".length) : undefined;
|
|
297
|
+
if (!serder || !hab || !["apply", "offer", "agree", "spurn", "grant"].includes(verb ?? "")) {
|
|
298
|
+
throw new ValidationError("No presentation was begun for this exchange");
|
|
299
|
+
}
|
|
300
|
+
return { serder, hab, verb: verb };
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Pure read of one presentation: the live table, what ended or delivered in this process, and what the stored
|
|
304
|
+
* exchanges prove (the peer's answer, when one was stored; see the module doc for what a reload loses). A
|
|
305
|
+
* signed exchange no live delivery holds and nobody answered reads `interrupted`, or `expired` past its
|
|
306
|
+
* deadline; that is a statement, not a write.
|
|
307
|
+
*
|
|
308
|
+
* @throws ValidationError when `said` is not a presentation exchange a local identifier signed.
|
|
309
|
+
*/
|
|
310
|
+
export function presentationStatus(ops, said) {
|
|
311
|
+
const { deps } = ops, ended = ops.settled.get(said), live = ops.live.get(said);
|
|
312
|
+
const answered = (verb, deliveries) => {
|
|
313
|
+
const answer = deps.hby.db.erpy.get([said])?.qb64;
|
|
314
|
+
const response = answer ? { said: answer, route: deps.hby.db.exns.get([answer])?.route ?? null } : undefined;
|
|
315
|
+
return { state: "done", verb, phase: "delivered", deliveries, response };
|
|
316
|
+
};
|
|
317
|
+
if (ended && ended.state !== "done")
|
|
318
|
+
return { state: ended.state, verb: ended.verb, reason: ended.reason };
|
|
319
|
+
if (ended)
|
|
320
|
+
return answered(ended.verb, ended.deliveries);
|
|
321
|
+
if (live && !lapsed(deps.clock, live.deadline)) {
|
|
322
|
+
return {
|
|
323
|
+
state: "active",
|
|
324
|
+
verb: live.verb,
|
|
325
|
+
phase: "delivering",
|
|
326
|
+
deadline: live.deadline,
|
|
327
|
+
...(live.outbox.failure && { failure: live.outbox.failure }),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const { serder, verb } = signed(deps, said);
|
|
331
|
+
if (deps.hby.db.erpy.get([said]))
|
|
332
|
+
return answered(verb);
|
|
333
|
+
if (lapsed(deps.clock, deps.exc.exchangeDeadline(serder) ?? undefined)) {
|
|
334
|
+
return { state: "expired", verb, reason: EXPIRED };
|
|
335
|
+
}
|
|
336
|
+
return { state: "interrupted", verb, reason: RESEND };
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Observe until the presentation is delivered or ended, or the budget expires. Starts no worker and drives
|
|
340
|
+
* nothing: someone else must call `processOnce`.
|
|
341
|
+
*/
|
|
342
|
+
export function* waitForPresentation(ops, said, { timeoutMs, clock = ops.deps.clock, until = (status) => status.state !== "active" }) {
|
|
343
|
+
const settled = yield* observeUntil(() => until(presentationStatus(ops, said)), { timeoutMs, clock });
|
|
344
|
+
const status = presentationStatus(ops, said);
|
|
345
|
+
return settled ? { outcome: "settled", status } : { outcome: "timed-out", status, timeoutMs };
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Local abandon: stop delivering and read `abandoned` until the process ends. Does not message the peer and
|
|
349
|
+
* does not retract an exchange already delivered. Does nothing to a presentation that is already delivered
|
|
350
|
+
* or ended.
|
|
351
|
+
*
|
|
352
|
+
* @throws ValidationError when `said` is not a presentation exchange a local identifier signed.
|
|
353
|
+
*/
|
|
354
|
+
export function abandonPresentation(ops, said, reason = "Abandoned by the user") {
|
|
355
|
+
const status = presentationStatus(ops, said);
|
|
356
|
+
if (status.state === "done" || status.state === "abandoned" || status.state === "failed")
|
|
357
|
+
return;
|
|
358
|
+
const live = ops.live.get(said);
|
|
359
|
+
if (live)
|
|
360
|
+
ops.end(live, "abandoned", reason);
|
|
361
|
+
else {
|
|
362
|
+
ops.settled.set(said, { verb: status.verb, state: "abandoned", reason });
|
|
363
|
+
ops.deps.changes?.push({ kind: "presentation", id: said });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Deliver a presentation again after a restart, or after delivery failed or was abandoned: rebuilds the wire
|
|
368
|
+
* of the stored signed exchange from its retained signatures or source seal and nests, so the bytes are the
|
|
369
|
+
* ones first delivered and nothing is signed. Queues them like `present`, with a fresh outbox; return
|
|
370
|
+
* is after the queueing, not after delivery.
|
|
371
|
+
*
|
|
372
|
+
* @throws ValidationError for an exchange no local identifier signed, one the peer already answered, one past
|
|
373
|
+
* its deadline, one already being delivered, or one whose retained factors no longer authenticate.
|
|
374
|
+
*/
|
|
375
|
+
export function* resendPresentation(ops, said) {
|
|
376
|
+
const { deps } = ops, { serder, hab, verb } = signed(deps, said);
|
|
377
|
+
const status = presentationStatus(ops, said);
|
|
378
|
+
if (status.state === "active")
|
|
379
|
+
throw new ValidationError("This presentation is already being delivered");
|
|
380
|
+
if (deps.hby.db.erpy.get([said]))
|
|
381
|
+
throw new ValidationError("The peer already answered this presentation");
|
|
382
|
+
const deadline = deps.exc.exchangeDeadline(serder) ?? undefined;
|
|
383
|
+
if (lapsed(deps.clock, deadline))
|
|
384
|
+
throw new ValidationError(EXPIRED);
|
|
385
|
+
const retained = deps.exc.retainedInput(said);
|
|
386
|
+
if (!retained)
|
|
387
|
+
throw new ValidationError("The signed exchange no longer authenticates from stored factors");
|
|
388
|
+
const discloser = discloserFor(deps, hab);
|
|
389
|
+
let support = new Uint8Array();
|
|
390
|
+
if (verb === "grant") {
|
|
391
|
+
const raw = concatBytes(Counter.makeGVC(Vrsn_2_0), ...yield* call(() => Promise.all((retained.nests ?? []).map((nest) => collectPayload(framePayload(nest))))));
|
|
392
|
+
support = discloser.proofSupport(raw, hab);
|
|
393
|
+
}
|
|
394
|
+
else if (verb === "agree" && retained.sourceSeals?.length)
|
|
395
|
+
support = discloser.kel(hab);
|
|
396
|
+
const wire = concatBytes(discloser.kel(hab), support, yield* storedExchangeWire(retained));
|
|
397
|
+
const recipient = String(serder.sad.ri);
|
|
398
|
+
queue(ops, { said, verb, hab, recipient, wire, deadline });
|
|
399
|
+
deps.changes?.push({ kind: "presentation", id: said });
|
|
400
|
+
return { said, recipient, wire };
|
|
401
|
+
}
|