@harrylabsj/kiwi 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +150 -0
- package/contracts/candidate-agent-dto-1.0.README.md +39 -0
- package/contracts/candidate-agent-dto-1.0.schema.json +172 -0
- package/contracts/interop/kiwi-buyer-message-send.json +43 -0
- package/contracts/interop/knp-data-part-examples.json +243 -0
- package/contracts/kiwi-catalog/1.0/agent-record.schema.json +78 -0
- package/contracts/kiwi-catalog/1.0/listing-record.schema.json +88 -0
- package/contracts/kiwi-catalog/1.0/listing-search-result.schema.json +60 -0
- package/contracts/negotiation/1.0/schema.json +501 -0
- package/contracts/shopping.negotiation/0.1/capabilities.schema.json +47 -0
- package/contracts/shopping.negotiation/0.1/decision.schema.json +120 -0
- package/contracts/shopping.negotiation/0.1/policy-result.schema.json +52 -0
- package/contracts/shopping.negotiation/0.1/snapshot.schema.json +172 -0
- package/dist/a2a/client/client.d.ts +33 -0
- package/dist/a2a/client/client.js +161 -0
- package/dist/a2a/client/client.js.map +1 -0
- package/dist/a2a/client/error.d.ts +35 -0
- package/dist/a2a/client/error.js +34 -0
- package/dist/a2a/client/error.js.map +1 -0
- package/dist/a2a/client/index.d.ts +29 -0
- package/dist/a2a/client/index.js +26 -0
- package/dist/a2a/client/index.js.map +1 -0
- package/dist/a2a/client/jsonrpc.d.ts +49 -0
- package/dist/a2a/client/jsonrpc.js +85 -0
- package/dist/a2a/client/jsonrpc.js.map +1 -0
- package/dist/a2a/client/parse.d.ts +18 -0
- package/dist/a2a/client/parse.js +134 -0
- package/dist/a2a/client/parse.js.map +1 -0
- package/dist/a2a/client/types.d.ts +102 -0
- package/dist/a2a/client/types.js +26 -0
- package/dist/a2a/client/types.js.map +1 -0
- package/dist/a2a/client/url-policy.d.ts +44 -0
- package/dist/a2a/client/url-policy.js +242 -0
- package/dist/a2a/client/url-policy.js.map +1 -0
- package/dist/a2a/negotiate.d.ts +68 -0
- package/dist/a2a/negotiate.js +288 -0
- package/dist/a2a/negotiate.js.map +1 -0
- package/dist/a2a/node.d.ts +37 -0
- package/dist/a2a/node.js +155 -0
- package/dist/a2a/node.js.map +1 -0
- package/dist/a2a/server/auth.d.ts +38 -0
- package/dist/a2a/server/auth.js +112 -0
- package/dist/a2a/server/auth.js.map +1 -0
- package/dist/a2a/server/card.d.ts +19 -0
- package/dist/a2a/server/card.js +81 -0
- package/dist/a2a/server/card.js.map +1 -0
- package/dist/a2a/server/errors.d.ts +109 -0
- package/dist/a2a/server/errors.js +178 -0
- package/dist/a2a/server/errors.js.map +1 -0
- package/dist/a2a/server/handler.d.ts +22 -0
- package/dist/a2a/server/handler.js +57 -0
- package/dist/a2a/server/handler.js.map +1 -0
- package/dist/a2a/server/inbound-message.d.ts +37 -0
- package/dist/a2a/server/inbound-message.js +104 -0
- package/dist/a2a/server/inbound-message.js.map +1 -0
- package/dist/a2a/server/index.d.ts +43 -0
- package/dist/a2a/server/index.js +42 -0
- package/dist/a2a/server/index.js.map +1 -0
- package/dist/a2a/server/merchant-handler.d.ts +69 -0
- package/dist/a2a/server/merchant-handler.js +316 -0
- package/dist/a2a/server/merchant-handler.js.map +1 -0
- package/dist/a2a/server/pipeline.d.ts +69 -0
- package/dist/a2a/server/pipeline.js +329 -0
- package/dist/a2a/server/pipeline.js.map +1 -0
- package/dist/a2a/server/server.d.ts +64 -0
- package/dist/a2a/server/server.js +420 -0
- package/dist/a2a/server/server.js.map +1 -0
- package/dist/a2a/server/task-registry.d.ts +31 -0
- package/dist/a2a/server/task-registry.js +67 -0
- package/dist/a2a/server/task-registry.js.map +1 -0
- package/dist/a2a/server/throttle.d.ts +154 -0
- package/dist/a2a/server/throttle.js +289 -0
- package/dist/a2a/server/throttle.js.map +1 -0
- package/dist/a2a/server/types.d.ts +191 -0
- package/dist/a2a/server/types.js +17 -0
- package/dist/a2a/server/types.js.map +1 -0
- package/dist/a2a/server/ucp.d.ts +49 -0
- package/dist/a2a/server/ucp.js +85 -0
- package/dist/a2a/server/ucp.js.map +1 -0
- package/dist/a2a/task/index.d.ts +24 -0
- package/dist/a2a/task/index.js +22 -0
- package/dist/a2a/task/index.js.map +1 -0
- package/dist/a2a/task/ledger.d.ts +48 -0
- package/dist/a2a/task/ledger.js +65 -0
- package/dist/a2a/task/ledger.js.map +1 -0
- package/dist/a2a/task/poller.d.ts +93 -0
- package/dist/a2a/task/poller.js +184 -0
- package/dist/a2a/task/poller.js.map +1 -0
- package/dist/a2a/task/state.d.ts +72 -0
- package/dist/a2a/task/state.js +119 -0
- package/dist/a2a/task/state.js.map +1 -0
- package/dist/a2a/ucp-agent.d.ts +49 -0
- package/dist/a2a/ucp-agent.js +78 -0
- package/dist/a2a/ucp-agent.js.map +1 -0
- package/dist/agent/agent-db.d.ts +31 -0
- package/dist/agent/agent-db.js +91 -0
- package/dist/agent/agent-db.js.map +1 -0
- package/dist/agent/buyer/buyer-tools.d.ts +70 -0
- package/dist/agent/buyer/buyer-tools.js +1353 -0
- package/dist/agent/buyer/buyer-tools.js.map +1 -0
- package/dist/agent/buyer/ranker.d.ts +53 -0
- package/dist/agent/buyer/ranker.js +153 -0
- package/dist/agent/buyer/ranker.js.map +1 -0
- package/dist/agent/buyer/scheduler.d.ts +58 -0
- package/dist/agent/buyer/scheduler.js +317 -0
- package/dist/agent/buyer/scheduler.js.map +1 -0
- package/dist/agent/buyer/search-loop.d.ts +42 -0
- package/dist/agent/buyer/search-loop.js +280 -0
- package/dist/agent/buyer/search-loop.js.map +1 -0
- package/dist/agent/buyer/task-store.d.ts +178 -0
- package/dist/agent/buyer/task-store.js +637 -0
- package/dist/agent/buyer/task-store.js.map +1 -0
- package/dist/agent/buyer/types.d.ts +222 -0
- package/dist/agent/buyer/types.js +124 -0
- package/dist/agent/buyer/types.js.map +1 -0
- package/dist/agent/chat-tools.d.ts +41 -0
- package/dist/agent/chat-tools.js +193 -0
- package/dist/agent/chat-tools.js.map +1 -0
- package/dist/agent/chat-tui.d.ts +49 -0
- package/dist/agent/chat-tui.js +314 -0
- package/dist/agent/chat-tui.js.map +1 -0
- package/dist/agent/connector/fake-connector.d.ts +50 -0
- package/dist/agent/connector/fake-connector.js +138 -0
- package/dist/agent/connector/fake-connector.js.map +1 -0
- package/dist/agent/connector/http-connector.d.ts +49 -0
- package/dist/agent/connector/http-connector.js +208 -0
- package/dist/agent/connector/http-connector.js.map +1 -0
- package/dist/agent/connector/types.d.ts +103 -0
- package/dist/agent/connector/types.js +97 -0
- package/dist/agent/connector/types.js.map +1 -0
- package/dist/agent/fake-chat-model.d.ts +22 -0
- package/dist/agent/fake-chat-model.js +134 -0
- package/dist/agent/fake-chat-model.js.map +1 -0
- package/dist/agent/kernel.d.ts +258 -0
- package/dist/agent/kernel.js +1099 -0
- package/dist/agent/kernel.js.map +1 -0
- package/dist/agent/memory/schema.d.ts +32 -0
- package/dist/agent/memory/schema.js +291 -0
- package/dist/agent/memory/schema.js.map +1 -0
- package/dist/agent/memory/store.d.ts +193 -0
- package/dist/agent/memory/store.js +881 -0
- package/dist/agent/memory/store.js.map +1 -0
- package/dist/agent/memory/types.d.ts +139 -0
- package/dist/agent/memory/types.js +119 -0
- package/dist/agent/memory/types.js.map +1 -0
- package/dist/agent/memory/vault.d.ts +49 -0
- package/dist/agent/memory/vault.js +125 -0
- package/dist/agent/memory/vault.js.map +1 -0
- package/dist/agent/merchant/action-candidate.d.ts +106 -0
- package/dist/agent/merchant/action-candidate.js +241 -0
- package/dist/agent/merchant/action-candidate.js.map +1 -0
- package/dist/agent/merchant/credential-broker.d.ts +67 -0
- package/dist/agent/merchant/credential-broker.js +76 -0
- package/dist/agent/merchant/credential-broker.js.map +1 -0
- package/dist/agent/merchant/fake-merchant-client.d.ts +47 -0
- package/dist/agent/merchant/fake-merchant-client.js +143 -0
- package/dist/agent/merchant/fake-merchant-client.js.map +1 -0
- package/dist/agent/merchant/merchant-client.d.ts +49 -0
- package/dist/agent/merchant/merchant-client.js +186 -0
- package/dist/agent/merchant/merchant-client.js.map +1 -0
- package/dist/agent/merchant/merchant-tools.d.ts +74 -0
- package/dist/agent/merchant/merchant-tools.js +582 -0
- package/dist/agent/merchant/merchant-tools.js.map +1 -0
- package/dist/agent/merchant/types.d.ts +119 -0
- package/dist/agent/merchant/types.js +133 -0
- package/dist/agent/merchant/types.js.map +1 -0
- package/dist/agent/mode.d.ts +32 -0
- package/dist/agent/mode.js +34 -0
- package/dist/agent/mode.js.map +1 -0
- package/dist/agent/negotiation-chat.d.ts +81 -0
- package/dist/agent/negotiation-chat.js +330 -0
- package/dist/agent/negotiation-chat.js.map +1 -0
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +164 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +26 -0
- package/dist/agent/system-prompt.js +77 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/agent/write-gate.d.ts +98 -0
- package/dist/agent/write-gate.js +76 -0
- package/dist/agent/write-gate.js.map +1 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +1139 -0
- package/dist/cli.js.map +1 -0
- package/dist/commerce/data-source.d.ts +88 -0
- package/dist/commerce/data-source.js +25 -0
- package/dist/commerce/data-source.js.map +1 -0
- package/dist/commerce/erp-source.d.ts +51 -0
- package/dist/commerce/erp-source.js +184 -0
- package/dist/commerce/erp-source.js.map +1 -0
- package/dist/commerce/fake-client.d.ts +167 -0
- package/dist/commerce/fake-client.js +549 -0
- package/dist/commerce/fake-client.js.map +1 -0
- package/dist/commerce/http-client.d.ts +73 -0
- package/dist/commerce/http-client.js +284 -0
- package/dist/commerce/http-client.js.map +1 -0
- package/dist/commerce/local-db-source.d.ts +50 -0
- package/dist/commerce/local-db-source.js +162 -0
- package/dist/commerce/local-db-source.js.map +1 -0
- package/dist/commerce/shopping-cli-source.d.ts +57 -0
- package/dist/commerce/shopping-cli-source.js +206 -0
- package/dist/commerce/shopping-cli-source.js.map +1 -0
- package/dist/commerce/types.d.ts +146 -0
- package/dist/commerce/types.js +31 -0
- package/dist/commerce/types.js.map +1 -0
- package/dist/config/profile.d.ts +122 -0
- package/dist/config/profile.js +386 -0
- package/dist/config/profile.js.map +1 -0
- package/dist/contracts/negotiation-schema.d.ts +28 -0
- package/dist/contracts/negotiation-schema.js +101 -0
- package/dist/contracts/negotiation-schema.js.map +1 -0
- package/dist/contracts/schemas.d.ts +31 -0
- package/dist/contracts/schemas.js +122 -0
- package/dist/contracts/schemas.js.map +1 -0
- package/dist/counterparty/a2a-direct/index.d.ts +41 -0
- package/dist/counterparty/a2a-direct/index.js +330 -0
- package/dist/counterparty/a2a-direct/index.js.map +1 -0
- package/dist/counterparty/channel.d.ts +200 -0
- package/dist/counterparty/channel.js +61 -0
- package/dist/counterparty/channel.js.map +1 -0
- package/dist/counterparty/index.d.ts +28 -0
- package/dist/counterparty/index.js +24 -0
- package/dist/counterparty/index.js.map +1 -0
- package/dist/counterparty/platform-api/index.d.ts +41 -0
- package/dist/counterparty/platform-api/index.js +65 -0
- package/dist/counterparty/platform-api/index.js.map +1 -0
- package/dist/counterparty/registry.d.ts +51 -0
- package/dist/counterparty/registry.js +71 -0
- package/dist/counterparty/registry.js.map +1 -0
- package/dist/counterparty/shopping-cli-hosted/index.d.ts +36 -0
- package/dist/counterparty/shopping-cli-hosted/index.js +337 -0
- package/dist/counterparty/shopping-cli-hosted/index.js.map +1 -0
- package/dist/discovery/agent-card/error.d.ts +28 -0
- package/dist/discovery/agent-card/error.js +31 -0
- package/dist/discovery/agent-card/error.js.map +1 -0
- package/dist/discovery/agent-card/extensions.d.ts +20 -0
- package/dist/discovery/agent-card/extensions.js +59 -0
- package/dist/discovery/agent-card/extensions.js.map +1 -0
- package/dist/discovery/agent-card/index.d.ts +29 -0
- package/dist/discovery/agent-card/index.js +38 -0
- package/dist/discovery/agent-card/index.js.map +1 -0
- package/dist/discovery/agent-card/secrets.d.ts +30 -0
- package/dist/discovery/agent-card/secrets.js +240 -0
- package/dist/discovery/agent-card/secrets.js.map +1 -0
- package/dist/discovery/agent-card/types.d.ts +110 -0
- package/dist/discovery/agent-card/types.js +37 -0
- package/dist/discovery/agent-card/types.js.map +1 -0
- package/dist/discovery/agent-card/validate.d.ts +31 -0
- package/dist/discovery/agent-card/validate.js +210 -0
- package/dist/discovery/agent-card/validate.js.map +1 -0
- package/dist/discovery/capability/error.d.ts +23 -0
- package/dist/discovery/capability/error.js +28 -0
- package/dist/discovery/capability/error.js.map +1 -0
- package/dist/discovery/capability/index.d.ts +21 -0
- package/dist/discovery/capability/index.js +21 -0
- package/dist/discovery/capability/index.js.map +1 -0
- package/dist/discovery/capability/intersect.d.ts +56 -0
- package/dist/discovery/capability/intersect.js +137 -0
- package/dist/discovery/capability/intersect.js.map +1 -0
- package/dist/discovery/catalog-source/errors.d.ts +32 -0
- package/dist/discovery/catalog-source/errors.js +41 -0
- package/dist/discovery/catalog-source/errors.js.map +1 -0
- package/dist/discovery/catalog-source/index.d.ts +30 -0
- package/dist/discovery/catalog-source/index.js +29 -0
- package/dist/discovery/catalog-source/index.js.map +1 -0
- package/dist/discovery/catalog-source/kiwi-record.d.ts +183 -0
- package/dist/discovery/catalog-source/kiwi-record.js +72 -0
- package/dist/discovery/catalog-source/kiwi-record.js.map +1 -0
- package/dist/discovery/catalog-source/kiwi-schema.d.ts +33 -0
- package/dist/discovery/catalog-source/kiwi-schema.js +106 -0
- package/dist/discovery/catalog-source/kiwi-schema.js.map +1 -0
- package/dist/discovery/catalog-source/kiwi-source.d.ts +38 -0
- package/dist/discovery/catalog-source/kiwi-source.js +318 -0
- package/dist/discovery/catalog-source/kiwi-source.js.map +1 -0
- package/dist/discovery/catalog-source/register.d.ts +48 -0
- package/dist/discovery/catalog-source/register.js +83 -0
- package/dist/discovery/catalog-source/register.js.map +1 -0
- package/dist/discovery/catalog-source/schema.d.ts +21 -0
- package/dist/discovery/catalog-source/schema.js +63 -0
- package/dist/discovery/catalog-source/schema.js.map +1 -0
- package/dist/discovery/catalog-source/source.d.ts +45 -0
- package/dist/discovery/catalog-source/source.js +197 -0
- package/dist/discovery/catalog-source/source.js.map +1 -0
- package/dist/discovery/catalog-source/types.d.ts +122 -0
- package/dist/discovery/catalog-source/types.js +30 -0
- package/dist/discovery/catalog-source/types.js.map +1 -0
- package/dist/discovery/index.d.ts +25 -0
- package/dist/discovery/index.js +25 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/resolve.d.ts +175 -0
- package/dist/discovery/resolve.js +367 -0
- package/dist/discovery/resolve.js.map +1 -0
- package/dist/discovery/ucp/error.d.ts +25 -0
- package/dist/discovery/ucp/error.js +27 -0
- package/dist/discovery/ucp/error.js.map +1 -0
- package/dist/discovery/ucp/index.d.ts +33 -0
- package/dist/discovery/ucp/index.js +28 -0
- package/dist/discovery/ucp/index.js.map +1 -0
- package/dist/discovery/ucp/intersect.d.ts +148 -0
- package/dist/discovery/ucp/intersect.js +312 -0
- package/dist/discovery/ucp/intersect.js.map +1 -0
- package/dist/discovery/ucp/resolver.d.ts +62 -0
- package/dist/discovery/ucp/resolver.js +214 -0
- package/dist/discovery/ucp/resolver.js.map +1 -0
- package/dist/discovery/ucp/types.d.ts +97 -0
- package/dist/discovery/ucp/types.js +103 -0
- package/dist/discovery/ucp/types.js.map +1 -0
- package/dist/discovery/ucp/validate.d.ts +38 -0
- package/dist/discovery/ucp/validate.js +232 -0
- package/dist/discovery/ucp/validate.js.map +1 -0
- package/dist/discovery/ucp/vendor.d.ts +60 -0
- package/dist/discovery/ucp/vendor.js +61 -0
- package/dist/discovery/ucp/vendor.js.map +1 -0
- package/dist/doctor.d.ts +26 -0
- package/dist/doctor.js +113 -0
- package/dist/doctor.js.map +1 -0
- package/dist/exit-codes.d.ts +26 -0
- package/dist/exit-codes.js +27 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/fanout/disclosure.d.ts +138 -0
- package/dist/fanout/disclosure.js +188 -0
- package/dist/fanout/disclosure.js.map +1 -0
- package/dist/fanout/index.d.ts +32 -0
- package/dist/fanout/index.js +30 -0
- package/dist/fanout/index.js.map +1 -0
- package/dist/fanout/orchestrator.d.ts +153 -0
- package/dist/fanout/orchestrator.js +439 -0
- package/dist/fanout/orchestrator.js.map +1 -0
- package/dist/fanout/policy.d.ts +128 -0
- package/dist/fanout/policy.js +130 -0
- package/dist/fanout/policy.js.map +1 -0
- package/dist/handoff/acp-commerce.d.ts +58 -0
- package/dist/handoff/acp-commerce.js +69 -0
- package/dist/handoff/acp-commerce.js.map +1 -0
- package/dist/handoff/authorization.d.ts +127 -0
- package/dist/handoff/authorization.js +107 -0
- package/dist/handoff/authorization.js.map +1 -0
- package/dist/handoff/candidate.d.ts +94 -0
- package/dist/handoff/candidate.js +172 -0
- package/dist/handoff/candidate.js.map +1 -0
- package/dist/handoff/channel.d.ts +88 -0
- package/dist/handoff/channel.js +189 -0
- package/dist/handoff/channel.js.map +1 -0
- package/dist/handoff/completion.d.ts +44 -0
- package/dist/handoff/completion.js +136 -0
- package/dist/handoff/completion.js.map +1 -0
- package/dist/handoff/delivery.d.ts +59 -0
- package/dist/handoff/delivery.js +185 -0
- package/dist/handoff/delivery.js.map +1 -0
- package/dist/handoff/destination.d.ts +39 -0
- package/dist/handoff/destination.js +99 -0
- package/dist/handoff/destination.js.map +1 -0
- package/dist/handoff/errors.d.ts +34 -0
- package/dist/handoff/errors.js +47 -0
- package/dist/handoff/errors.js.map +1 -0
- package/dist/handoff/idempotency.d.ts +51 -0
- package/dist/handoff/idempotency.js +168 -0
- package/dist/handoff/idempotency.js.map +1 -0
- package/dist/handoff/index.d.ts +46 -0
- package/dist/handoff/index.js +48 -0
- package/dist/handoff/index.js.map +1 -0
- package/dist/handoff/ledger.d.ts +94 -0
- package/dist/handoff/ledger.js +195 -0
- package/dist/handoff/ledger.js.map +1 -0
- package/dist/handoff/lifecycle.d.ts +29 -0
- package/dist/handoff/lifecycle.js +102 -0
- package/dist/handoff/lifecycle.js.map +1 -0
- package/dist/handoff/metrics.d.ts +56 -0
- package/dist/handoff/metrics.js +78 -0
- package/dist/handoff/metrics.js.map +1 -0
- package/dist/handoff/operator-approval.d.ts +143 -0
- package/dist/handoff/operator-approval.js +287 -0
- package/dist/handoff/operator-approval.js.map +1 -0
- package/dist/handoff/order-record.d.ts +104 -0
- package/dist/handoff/order-record.js +235 -0
- package/dist/handoff/order-record.js.map +1 -0
- package/dist/handoff/package.d.ts +102 -0
- package/dist/handoff/package.js +132 -0
- package/dist/handoff/package.js.map +1 -0
- package/dist/handoff/transaction.d.ts +96 -0
- package/dist/handoff/transaction.js +263 -0
- package/dist/handoff/transaction.js.map +1 -0
- package/dist/handoff/ucp-checkout/cart-channel.d.ts +111 -0
- package/dist/handoff/ucp-checkout/cart-channel.js +370 -0
- package/dist/handoff/ucp-checkout/cart-channel.js.map +1 -0
- package/dist/handoff/ucp-checkout/cart-parse.d.ts +22 -0
- package/dist/handoff/ucp-checkout/cart-parse.js +102 -0
- package/dist/handoff/ucp-checkout/cart-parse.js.map +1 -0
- package/dist/handoff/ucp-checkout/cart-types.d.ts +93 -0
- package/dist/handoff/ucp-checkout/cart-types.js +38 -0
- package/dist/handoff/ucp-checkout/cart-types.js.map +1 -0
- package/dist/handoff/ucp-checkout/channel.d.ts +159 -0
- package/dist/handoff/ucp-checkout/channel.js +636 -0
- package/dist/handoff/ucp-checkout/channel.js.map +1 -0
- package/dist/handoff/ucp-checkout/client.d.ts +88 -0
- package/dist/handoff/ucp-checkout/client.js +228 -0
- package/dist/handoff/ucp-checkout/client.js.map +1 -0
- package/dist/handoff/ucp-checkout/endpoint.d.ts +36 -0
- package/dist/handoff/ucp-checkout/endpoint.js +145 -0
- package/dist/handoff/ucp-checkout/endpoint.js.map +1 -0
- package/dist/handoff/ucp-checkout/index.d.ts +35 -0
- package/dist/handoff/ucp-checkout/index.js +36 -0
- package/dist/handoff/ucp-checkout/index.js.map +1 -0
- package/dist/handoff/ucp-checkout/parse.d.ts +71 -0
- package/dist/handoff/ucp-checkout/parse.js +349 -0
- package/dist/handoff/ucp-checkout/parse.js.map +1 -0
- package/dist/handoff/ucp-checkout/totals.d.ts +41 -0
- package/dist/handoff/ucp-checkout/totals.js +36 -0
- package/dist/handoff/ucp-checkout/totals.js.map +1 -0
- package/dist/handoff/ucp-checkout/types.d.ts +149 -0
- package/dist/handoff/ucp-checkout/types.js +58 -0
- package/dist/handoff/ucp-checkout/types.js.map +1 -0
- package/dist/handoff/url-safety.d.ts +44 -0
- package/dist/handoff/url-safety.js +121 -0
- package/dist/handoff/url-safety.js.map +1 -0
- package/dist/i18n.d.ts +24 -0
- package/dist/i18n.js +27 -0
- package/dist/i18n.js.map +1 -0
- package/dist/negotiation/action-candidate.d.ts +97 -0
- package/dist/negotiation/action-candidate.js +160 -0
- package/dist/negotiation/action-candidate.js.map +1 -0
- package/dist/negotiation/condition/evaluator.d.ts +36 -0
- package/dist/negotiation/condition/evaluator.js +123 -0
- package/dist/negotiation/condition/evaluator.js.map +1 -0
- package/dist/negotiation/context-map/index.d.ts +23 -0
- package/dist/negotiation/context-map/index.js +22 -0
- package/dist/negotiation/context-map/index.js.map +1 -0
- package/dist/negotiation/context-map/store.d.ts +51 -0
- package/dist/negotiation/context-map/store.js +186 -0
- package/dist/negotiation/context-map/store.js.map +1 -0
- package/dist/negotiation/context-map/types.d.ts +29 -0
- package/dist/negotiation/context-map/types.js +57 -0
- package/dist/negotiation/context-map/types.js.map +1 -0
- package/dist/negotiation/domain/common.d.ts +95 -0
- package/dist/negotiation/domain/common.js +216 -0
- package/dist/negotiation/domain/common.js.map +1 -0
- package/dist/negotiation/domain/envelope.d.ts +55 -0
- package/dist/negotiation/domain/envelope.js +110 -0
- package/dist/negotiation/domain/envelope.js.map +1 -0
- package/dist/negotiation/domain/identifiers.d.ts +65 -0
- package/dist/negotiation/domain/identifiers.js +130 -0
- package/dist/negotiation/domain/identifiers.js.map +1 -0
- package/dist/negotiation/domain/objects.d.ts +149 -0
- package/dist/negotiation/domain/objects.js +335 -0
- package/dist/negotiation/domain/objects.js.map +1 -0
- package/dist/negotiation/idempotency/index.d.ts +26 -0
- package/dist/negotiation/idempotency/index.js +25 -0
- package/dist/negotiation/idempotency/index.js.map +1 -0
- package/dist/negotiation/idempotency/store.d.ts +52 -0
- package/dist/negotiation/idempotency/store.js +189 -0
- package/dist/negotiation/idempotency/store.js.map +1 -0
- package/dist/negotiation/idempotency/types.d.ts +102 -0
- package/dist/negotiation/idempotency/types.js +47 -0
- package/dist/negotiation/idempotency/types.js.map +1 -0
- package/dist/negotiation/jcs.d.ts +21 -0
- package/dist/negotiation/jcs.js +114 -0
- package/dist/negotiation/jcs.js.map +1 -0
- package/dist/negotiation/ledger/event.d.ts +142 -0
- package/dist/negotiation/ledger/event.js +206 -0
- package/dist/negotiation/ledger/event.js.map +1 -0
- package/dist/negotiation/ledger/index.d.ts +26 -0
- package/dist/negotiation/ledger/index.js +25 -0
- package/dist/negotiation/ledger/index.js.map +1 -0
- package/dist/negotiation/ledger/store.d.ts +97 -0
- package/dist/negotiation/ledger/store.js +338 -0
- package/dist/negotiation/ledger/store.js.map +1 -0
- package/dist/negotiation/prompt.d.ts +34 -0
- package/dist/negotiation/prompt.js +113 -0
- package/dist/negotiation/prompt.js.map +1 -0
- package/dist/negotiation/recovery/index.d.ts +26 -0
- package/dist/negotiation/recovery/index.js +24 -0
- package/dist/negotiation/recovery/index.js.map +1 -0
- package/dist/negotiation/recovery/outbound.d.ts +49 -0
- package/dist/negotiation/recovery/outbound.js +34 -0
- package/dist/negotiation/recovery/outbound.js.map +1 -0
- package/dist/negotiation/recovery/recover.d.ts +59 -0
- package/dist/negotiation/recovery/recover.js +486 -0
- package/dist/negotiation/recovery/recover.js.map +1 -0
- package/dist/negotiation/recovery/types.d.ts +85 -0
- package/dist/negotiation/recovery/types.js +17 -0
- package/dist/negotiation/recovery/types.js.map +1 -0
- package/dist/negotiation/state/phase.d.ts +70 -0
- package/dist/negotiation/state/phase.js +200 -0
- package/dist/negotiation/state/phase.js.map +1 -0
- package/dist/negotiation/types.d.ts +139 -0
- package/dist/negotiation/types.js +24 -0
- package/dist/negotiation/types.js.map +1 -0
- package/dist/net/safe-http.d.ts +54 -0
- package/dist/net/safe-http.js +116 -0
- package/dist/net/safe-http.js.map +1 -0
- package/dist/operator/controller.d.ts +181 -0
- package/dist/operator/controller.js +784 -0
- package/dist/operator/controller.js.map +1 -0
- package/dist/operator/runner.d.ts +128 -0
- package/dist/operator/runner.js +248 -0
- package/dist/operator/runner.js.map +1 -0
- package/dist/operator/store.d.ts +39 -0
- package/dist/operator/store.js +169 -0
- package/dist/operator/store.js.map +1 -0
- package/dist/operator/strategy.d.ts +54 -0
- package/dist/operator/strategy.js +249 -0
- package/dist/operator/strategy.js.map +1 -0
- package/dist/operator/tui.d.ts +27 -0
- package/dist/operator/tui.js +395 -0
- package/dist/operator/tui.js.map +1 -0
- package/dist/operator/types.d.ts +224 -0
- package/dist/operator/types.js +17 -0
- package/dist/operator/types.js.map +1 -0
- package/dist/product-buyer.d.ts +74 -0
- package/dist/product-buyer.js +161 -0
- package/dist/product-buyer.js.map +1 -0
- package/dist/product-cli.d.ts +56 -0
- package/dist/product-cli.js +175 -0
- package/dist/product-cli.js.map +1 -0
- package/dist/product-compat.d.ts +50 -0
- package/dist/product-compat.js +63 -0
- package/dist/product-compat.js.map +1 -0
- package/dist/product-init.d.ts +73 -0
- package/dist/product-init.js +203 -0
- package/dist/product-init.js.map +1 -0
- package/dist/product-publish.d.ts +85 -0
- package/dist/product-publish.js +216 -0
- package/dist/product-publish.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/adapter.d.ts +42 -0
- package/dist/protocol/legacy-shopping-negotiation/adapter.js +561 -0
- package/dist/protocol/legacy-shopping-negotiation/adapter.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/mapping.d.ts +78 -0
- package/dist/protocol/legacy-shopping-negotiation/mapping.js +321 -0
- package/dist/protocol/legacy-shopping-negotiation/mapping.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/money.d.ts +49 -0
- package/dist/protocol/legacy-shopping-negotiation/money.js +70 -0
- package/dist/protocol/legacy-shopping-negotiation/money.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/types.d.ts +107 -0
- package/dist/protocol/legacy-shopping-negotiation/types.js +34 -0
- package/dist/protocol/legacy-shopping-negotiation/types.js.map +1 -0
- package/dist/runtime/buyer-policy.d.ts +58 -0
- package/dist/runtime/buyer-policy.js +89 -0
- package/dist/runtime/buyer-policy.js.map +1 -0
- package/dist/runtime/fake-model.d.ts +77 -0
- package/dist/runtime/fake-model.js +307 -0
- package/dist/runtime/fake-model.js.map +1 -0
- package/dist/runtime/foreground.d.ts +56 -0
- package/dist/runtime/foreground.js +97 -0
- package/dist/runtime/foreground.js.map +1 -0
- package/dist/runtime/heartbeat.d.ts +36 -0
- package/dist/runtime/heartbeat.js +49 -0
- package/dist/runtime/heartbeat.js.map +1 -0
- package/dist/runtime/merchant-turn.d.ts +35 -0
- package/dist/runtime/merchant-turn.js +20 -0
- package/dist/runtime/merchant-turn.js.map +1 -0
- package/dist/runtime/model.d.ts +40 -0
- package/dist/runtime/model.js +86 -0
- package/dist/runtime/model.js.map +1 -0
- package/dist/runtime/negotiation-turn.d.ts +101 -0
- package/dist/runtime/negotiation-turn.js +317 -0
- package/dist/runtime/negotiation-turn.js.map +1 -0
- package/dist/runtime/tools.d.ts +64 -0
- package/dist/runtime/tools.js +236 -0
- package/dist/runtime/tools.js.map +1 -0
- package/dist/supervisor/init.d.ts +31 -0
- package/dist/supervisor/init.js +222 -0
- package/dist/supervisor/init.js.map +1 -0
- package/dist/supervisor/logs.d.ts +28 -0
- package/dist/supervisor/logs.js +101 -0
- package/dist/supervisor/logs.js.map +1 -0
- package/dist/supervisor/manage.d.ts +72 -0
- package/dist/supervisor/manage.js +419 -0
- package/dist/supervisor/manage.js.map +1 -0
- package/dist/supervisor/manifest.d.ts +69 -0
- package/dist/supervisor/manifest.js +209 -0
- package/dist/supervisor/manifest.js.map +1 -0
- package/dist/supervisor/stack-config.d.ts +79 -0
- package/dist/supervisor/stack-config.js +262 -0
- package/dist/supervisor/stack-config.js.map +1 -0
- package/dist/supervisor/wrapper.d.ts +17 -0
- package/dist/supervisor/wrapper.js +138 -0
- package/dist/supervisor/wrapper.js.map +1 -0
- package/dist/trust/identity/auth-verifier.d.ts +96 -0
- package/dist/trust/identity/auth-verifier.js +166 -0
- package/dist/trust/identity/auth-verifier.js.map +1 -0
- package/dist/trust/identity/identity-binding.d.ts +63 -0
- package/dist/trust/identity/identity-binding.js +59 -0
- package/dist/trust/identity/identity-binding.js.map +1 -0
- package/dist/trust/identity/index.d.ts +38 -0
- package/dist/trust/identity/index.js +31 -0
- package/dist/trust/identity/index.js.map +1 -0
- package/dist/trust/identity/jws.d.ts +64 -0
- package/dist/trust/identity/jws.js +178 -0
- package/dist/trust/identity/jws.js.map +1 -0
- package/dist/trust/identity/keys.d.ts +71 -0
- package/dist/trust/identity/keys.js +118 -0
- package/dist/trust/identity/keys.js.map +1 -0
- package/dist/trust/identity/message-signature.d.ts +105 -0
- package/dist/trust/identity/message-signature.js +297 -0
- package/dist/trust/identity/message-signature.js.map +1 -0
- package/dist/trust/identity/nonce.d.ts +45 -0
- package/dist/trust/identity/nonce.js +50 -0
- package/dist/trust/identity/nonce.js.map +1 -0
- package/dist/trust/identity/signature-base.d.ts +84 -0
- package/dist/trust/identity/signature-base.js +261 -0
- package/dist/trust/identity/signature-base.js.map +1 -0
- package/dist/trust/identity/trust-policy.d.ts +92 -0
- package/dist/trust/identity/trust-policy.js +95 -0
- package/dist/trust/identity/trust-policy.js.map +1 -0
- package/dist/trust/index.d.ts +21 -0
- package/dist/trust/index.js +22 -0
- package/dist/trust/index.js.map +1 -0
- package/dist/trust/records/evaluator.d.ts +76 -0
- package/dist/trust/records/evaluator.js +122 -0
- package/dist/trust/records/evaluator.js.map +1 -0
- package/dist/trust/records/index.d.ts +28 -0
- package/dist/trust/records/index.js +26 -0
- package/dist/trust/records/index.js.map +1 -0
- package/dist/trust/records/store.d.ts +75 -0
- package/dist/trust/records/store.js +339 -0
- package/dist/trust/records/store.js.map +1 -0
- package/dist/trust/records/types.d.ts +159 -0
- package/dist/trust/records/types.js +40 -0
- package/dist/trust/records/types.js.map +1 -0
- package/dist/tui/banner.d.ts +46 -0
- package/dist/tui/banner.js +99 -0
- package/dist/tui/banner.js.map +1 -0
- package/dist/tui/styles.d.ts +70 -0
- package/dist/tui/styles.js +197 -0
- package/dist/tui/styles.js.map +1 -0
- package/dist/tui/theme.d.ts +63 -0
- package/dist/tui/theme.js +136 -0
- package/dist/tui/theme.js.map +1 -0
- package/examples/profiles/buyer.deepseek.yaml +34 -0
- package/examples/profiles/buyer.fake.yaml +36 -0
- package/examples/profiles/buyer.local.yaml +40 -0
- package/examples/profiles/merchant.deepseek.yaml +32 -0
- package/examples/profiles/merchant.fake.yaml +31 -0
- package/examples/profiles/merchant.local.yaml +34 -0
- package/package.json +55 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 协议级幂等(基线 §17 / 子规范 §20 Idempotency and Replay)。
|
|
18
|
+
*
|
|
19
|
+
* 主键 (sender_identity, message_id);同 id 同 digest 重放返回原结果,
|
|
20
|
+
* 同 id 异 digest 抛 idempotency_conflict(fail-closed)。retention 至少覆盖
|
|
21
|
+
* max(offer validity, task lifetime, 24h)。判定证据落 Ledger。
|
|
22
|
+
*/
|
|
23
|
+
export { IDEMPOTENCY_FLOOR_MS, IdempotencyConflictError, computeRetentionDeadline, idempotencyKey, } from "./types.js";
|
|
24
|
+
export type { IdempotencyCheckInput, IdempotencyCommitInput, IdempotencyDecision, IdempotencyRecord, RetentionInput, } from "./types.js";
|
|
25
|
+
export { IdempotencyStore } from "./store.js";
|
|
26
|
+
export type { IdempotencyStoreOptions } from "./store.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 协议级幂等(基线 §17 / 子规范 §20 Idempotency and Replay)。
|
|
18
|
+
*
|
|
19
|
+
* 主键 (sender_identity, message_id);同 id 同 digest 重放返回原结果,
|
|
20
|
+
* 同 id 异 digest 抛 idempotency_conflict(fail-closed)。retention 至少覆盖
|
|
21
|
+
* max(offer validity, task lifetime, 24h)。判定证据落 Ledger。
|
|
22
|
+
*/
|
|
23
|
+
export { IDEMPOTENCY_FLOOR_MS, IdempotencyConflictError, computeRetentionDeadline, idempotencyKey, } from "./types.js";
|
|
24
|
+
export { IdempotencyStore } from "./store.js";
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/negotiation/idempotency/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;GAMG;AACH,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,GACf,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import type { IdempotencyCheckInput, IdempotencyCommitInput, IdempotencyDecision, IdempotencyRecord } from "./types.js";
|
|
17
|
+
export interface IdempotencyStoreOptions {
|
|
18
|
+
/** 基础数据目录;幂等记录落在 `<dir>/idempotency/`。 */
|
|
19
|
+
dir: string;
|
|
20
|
+
/** 可注入时钟(RFC 3339);缺省用 new Date().toISOString()。 */
|
|
21
|
+
now?: () => string;
|
|
22
|
+
}
|
|
23
|
+
export declare class IdempotencyStore {
|
|
24
|
+
private readonly baseDir;
|
|
25
|
+
private readonly indexDir;
|
|
26
|
+
private readonly now;
|
|
27
|
+
constructor(options: IdempotencyStoreOptions);
|
|
28
|
+
private ensureIndexDir;
|
|
29
|
+
/** 记录文件名:`idem-<sha256(key)>.json`。key 内容在文件内自描述。 */
|
|
30
|
+
private filePathFor;
|
|
31
|
+
private writeFileAtomic;
|
|
32
|
+
private readRecord;
|
|
33
|
+
/** 记录是否已过期(expires_at <= nowIso)。 */
|
|
34
|
+
private isExpired;
|
|
35
|
+
/**
|
|
36
|
+
* 幂等三态判定(§20.1–§20.3)。只读,不写盘。
|
|
37
|
+
* 已过期记录视同「新消息」:retention 窗口外重放由状态校验决定,而非幂等层。
|
|
38
|
+
*/
|
|
39
|
+
check(input: IdempotencyCheckInput): IdempotencyDecision;
|
|
40
|
+
/**
|
|
41
|
+
* 提交一次成功处理。check 之后调用;若 check 与 commit 之间已有同 key 记录,
|
|
42
|
+
* 同 digest → 幂等返回既有记录;异 digest → 抛 IdempotencyConflictError。
|
|
43
|
+
*/
|
|
44
|
+
commit(input: IdempotencyCommitInput): IdempotencyRecord;
|
|
45
|
+
/** 读取记录(供恢复/调试);未知或已过期返回 null。 */
|
|
46
|
+
get(senderIdentity: string, messageId: string): IdempotencyRecord | null;
|
|
47
|
+
/** 过期记录清理;返回移除条数。不触碰 Ledger(§22:删除索引不影响审计链)。 */
|
|
48
|
+
sweep(nowIso?: string): number;
|
|
49
|
+
/** 索引规模(含过期,供诊断)。 */
|
|
50
|
+
count(): number;
|
|
51
|
+
private readRecordFromPath;
|
|
52
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 协议级幂等存储(基线 §17 / 子规范 §20)。
|
|
18
|
+
*
|
|
19
|
+
* 独立于 Ledger 持久化(幂等索引与审计链可分开部署),但每次 commit 记录都会
|
|
20
|
+
* 引用判定证据所在 Ledger 事件(ledger_event_id / ledger_event_digest,§22)。
|
|
21
|
+
*
|
|
22
|
+
* 判定流程(check → 执行/重放/冲突):
|
|
23
|
+
* 1. check((sender_identity, message_id, digest))
|
|
24
|
+
* - 无记录或已过期 → { status: "new" } 调用方执行业务效果
|
|
25
|
+
* - 同 key 同 digest → { status: "replayed" } 返回原结果,绝不重复执行
|
|
26
|
+
* - 同 key 异 digest → { status: "conflict" } 返回 idempotency_conflict,fail-closed
|
|
27
|
+
* 2. 执行成功后 commit(输入 + outcome + ledger 证据) → 落盘。
|
|
28
|
+
* commit 再次核验:key 已存在且 digest 不同 → 抛 IdempotencyConflictError
|
|
29
|
+
* (check 与 commit 之间的并发兜底)。
|
|
30
|
+
*
|
|
31
|
+
* retention(§20.5):expires_at = max(now + 24h, offer_valid_until,
|
|
32
|
+
* task_lifetime_until);sweep() 删除 expires_at <= now 的记录(可独立于 Ledger
|
|
33
|
+
* 执行 —— Ledger 是 append-only 审计链,删除幂等索引不影响审计完整性)。
|
|
34
|
+
*
|
|
35
|
+
* 本地持久化:目录 0700、文件 0600;写采用 supervisor/manifest.ts 的原子写
|
|
36
|
+
* (同目录临时文件 wx + fsync + rename)。
|
|
37
|
+
*/
|
|
38
|
+
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, renameSync, rmSync, writeSync, } from "node:fs";
|
|
39
|
+
import path from "node:path";
|
|
40
|
+
import { sha256Hex } from "../jcs.js";
|
|
41
|
+
import { IdempotencyConflictError, computeRetentionDeadline, idempotencyKey } from "./types.js";
|
|
42
|
+
let tmpSeq = 0;
|
|
43
|
+
export class IdempotencyStore {
|
|
44
|
+
baseDir;
|
|
45
|
+
indexDir;
|
|
46
|
+
now;
|
|
47
|
+
constructor(options) {
|
|
48
|
+
this.baseDir = options.dir;
|
|
49
|
+
this.indexDir = path.join(options.dir, "idempotency");
|
|
50
|
+
this.now = options.now ?? (() => new Date().toISOString());
|
|
51
|
+
}
|
|
52
|
+
ensureIndexDir() {
|
|
53
|
+
mkdirSync(this.indexDir, { recursive: true, mode: 0o700 });
|
|
54
|
+
chmodSync(this.indexDir, 0o700);
|
|
55
|
+
return this.indexDir;
|
|
56
|
+
}
|
|
57
|
+
/** 记录文件名:`idem-<sha256(key)>.json`。key 内容在文件内自描述。 */
|
|
58
|
+
filePathFor(key) {
|
|
59
|
+
const dir = this.ensureIndexDir();
|
|
60
|
+
const name = `idem-${sha256Hex(key)}.json`;
|
|
61
|
+
return path.resolve(dir, name);
|
|
62
|
+
}
|
|
63
|
+
writeFileAtomic(filePath, record) {
|
|
64
|
+
const tmp = `${filePath}.tmp-${process.pid}-${++tmpSeq}`;
|
|
65
|
+
const fd = openSync(tmp, "wx", 0o600);
|
|
66
|
+
try {
|
|
67
|
+
writeSync(fd, `${JSON.stringify(record)}\n`);
|
|
68
|
+
fsyncSync(fd);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
closeSync(fd);
|
|
72
|
+
}
|
|
73
|
+
renameSync(tmp, filePath);
|
|
74
|
+
chmodSync(filePath, 0o600);
|
|
75
|
+
}
|
|
76
|
+
readRecord(key) {
|
|
77
|
+
const filePath = this.filePathFor(key);
|
|
78
|
+
if (!existsSync(filePath))
|
|
79
|
+
return null;
|
|
80
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
81
|
+
if (parsed === null || typeof parsed !== "object")
|
|
82
|
+
return null;
|
|
83
|
+
const record = parsed;
|
|
84
|
+
if (typeof record.sender_identity !== "string" ||
|
|
85
|
+
typeof record.message_id !== "string" ||
|
|
86
|
+
typeof record.digest !== "string" ||
|
|
87
|
+
typeof record.negotiation_id !== "string" ||
|
|
88
|
+
typeof record.recorded_at !== "string" ||
|
|
89
|
+
typeof record.expires_at !== "string" ||
|
|
90
|
+
record.outcome === undefined ||
|
|
91
|
+
typeof record.outcome !== "object") {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return record;
|
|
95
|
+
}
|
|
96
|
+
/** 记录是否已过期(expires_at <= nowIso)。 */
|
|
97
|
+
isExpired(record, nowIso) {
|
|
98
|
+
return Date.parse(record.expires_at) <= Date.parse(nowIso);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 幂等三态判定(§20.1–§20.3)。只读,不写盘。
|
|
102
|
+
* 已过期记录视同「新消息」:retention 窗口外重放由状态校验决定,而非幂等层。
|
|
103
|
+
*/
|
|
104
|
+
check(input) {
|
|
105
|
+
const key = idempotencyKey(input.sender_identity, input.message_id);
|
|
106
|
+
const existing = this.readRecord(key);
|
|
107
|
+
if (existing === null || this.isExpired(existing, this.now())) {
|
|
108
|
+
return { status: "new", key };
|
|
109
|
+
}
|
|
110
|
+
if (existing.digest === input.digest) {
|
|
111
|
+
return { status: "replayed", key, record: existing };
|
|
112
|
+
}
|
|
113
|
+
return { status: "conflict", key, record: existing };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 提交一次成功处理。check 之后调用;若 check 与 commit 之间已有同 key 记录,
|
|
117
|
+
* 同 digest → 幂等返回既有记录;异 digest → 抛 IdempotencyConflictError。
|
|
118
|
+
*/
|
|
119
|
+
commit(input) {
|
|
120
|
+
const key = idempotencyKey(input.sender_identity, input.message_id);
|
|
121
|
+
const existing = this.readRecord(key);
|
|
122
|
+
if (existing !== null && !this.isExpired(existing, this.now())) {
|
|
123
|
+
if (existing.digest === input.digest)
|
|
124
|
+
return existing;
|
|
125
|
+
throw new IdempotencyConflictError(existing, input.digest);
|
|
126
|
+
}
|
|
127
|
+
const nowIso = this.now();
|
|
128
|
+
const expiresAt = computeRetentionDeadline(new Date(nowIso), input.retention).toISOString();
|
|
129
|
+
const record = {
|
|
130
|
+
sender_identity: input.sender_identity,
|
|
131
|
+
message_id: input.message_id,
|
|
132
|
+
digest: input.digest,
|
|
133
|
+
negotiation_id: input.negotiation_id,
|
|
134
|
+
outcome: input.outcome,
|
|
135
|
+
recorded_at: nowIso,
|
|
136
|
+
expires_at: expiresAt,
|
|
137
|
+
};
|
|
138
|
+
if (input.ledger_event_id !== undefined)
|
|
139
|
+
record.ledger_event_id = input.ledger_event_id;
|
|
140
|
+
if (input.ledger_event_digest !== undefined) {
|
|
141
|
+
record.ledger_event_digest = input.ledger_event_digest;
|
|
142
|
+
}
|
|
143
|
+
this.writeFileAtomic(this.filePathFor(key), record);
|
|
144
|
+
return record;
|
|
145
|
+
}
|
|
146
|
+
/** 读取记录(供恢复/调试);未知或已过期返回 null。 */
|
|
147
|
+
get(senderIdentity, messageId) {
|
|
148
|
+
const key = idempotencyKey(senderIdentity, messageId);
|
|
149
|
+
const record = this.readRecord(key);
|
|
150
|
+
if (record === null)
|
|
151
|
+
return null;
|
|
152
|
+
return this.isExpired(record, this.now()) ? null : record;
|
|
153
|
+
}
|
|
154
|
+
/** 过期记录清理;返回移除条数。不触碰 Ledger(§22:删除索引不影响审计链)。 */
|
|
155
|
+
sweep(nowIso) {
|
|
156
|
+
const dir = this.ensureIndexDir();
|
|
157
|
+
const now = nowIso ?? this.now();
|
|
158
|
+
let removed = 0;
|
|
159
|
+
for (const name of readdirSync(dir)) {
|
|
160
|
+
if (!name.startsWith("idem-") || !name.endsWith(".json"))
|
|
161
|
+
continue;
|
|
162
|
+
const filePath = path.join(dir, name);
|
|
163
|
+
try {
|
|
164
|
+
const record = this.readRecordFromPath(filePath);
|
|
165
|
+
if (record !== null && this.isExpired(record, now)) {
|
|
166
|
+
rmSync(filePath);
|
|
167
|
+
removed += 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// 单个损坏记录不阻断 sweep;继续清理其余。
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return removed;
|
|
175
|
+
}
|
|
176
|
+
/** 索引规模(含过期,供诊断)。 */
|
|
177
|
+
count() {
|
|
178
|
+
const dir = this.ensureIndexDir();
|
|
179
|
+
return readdirSync(dir).filter((name) => name.startsWith("idem-") && name.endsWith(".json"))
|
|
180
|
+
.length;
|
|
181
|
+
}
|
|
182
|
+
readRecordFromPath(filePath) {
|
|
183
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
184
|
+
if (parsed === null || typeof parsed !== "object")
|
|
185
|
+
return null;
|
|
186
|
+
return parsed;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/negotiation/idempotency/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 协议级幂等模型(基线 §17 / 子规范 §20 Idempotency and Replay)。
|
|
18
|
+
*
|
|
19
|
+
* 主键 (sender_identity, message_id):
|
|
20
|
+
* - same id + same digest → 不得重复执行业务效果,返回原结果或等价 ack(§20.2);
|
|
21
|
+
* - same id + different digest → idempotency_conflict,fail-closed,绝不应用新 payload
|
|
22
|
+
* (§20.3)。
|
|
23
|
+
*
|
|
24
|
+
* retention(§20.5 / 基线 §17):至少覆盖
|
|
25
|
+
* max(offer validity, task lifetime, 24 hours)。
|
|
26
|
+
* 参考实现以 24h 为地板,配合调用方给出的 offer_valid_until / task_lifetime_until
|
|
27
|
+
* 计算过期时间;过期后按「新消息」处理(允许再次进入状态校验)。
|
|
28
|
+
*
|
|
29
|
+
* 与 Ledger 的关系:幂等索引可独立存储,但判定证据落 Ledger —— 每次 commit 都应
|
|
30
|
+
* 携带对应的 ledger_event_id / ledger_event_digest,审计可交叉验证(§22)。
|
|
31
|
+
*/
|
|
32
|
+
/** 幂等记录:一次 (sender_identity, message_id) 的处理事实。 */
|
|
33
|
+
export interface IdempotencyRecord {
|
|
34
|
+
sender_identity: string;
|
|
35
|
+
message_id: string;
|
|
36
|
+
/** wire digest(KNP envelope digest,§19.2)。replay 时必须逐字节一致。 */
|
|
37
|
+
digest: string;
|
|
38
|
+
negotiation_id: string;
|
|
39
|
+
/** 原处理结果:成功(可带结构化 result)或协议错误(code 对齐 §18 词表)。 */
|
|
40
|
+
outcome: {
|
|
41
|
+
kind: "ok";
|
|
42
|
+
result?: unknown;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "error";
|
|
45
|
+
code: string;
|
|
46
|
+
message: string;
|
|
47
|
+
};
|
|
48
|
+
/** 判定证据的 Ledger 事件引用(§22:判定证据落 Ledger)。 */
|
|
49
|
+
ledger_event_id?: string;
|
|
50
|
+
ledger_event_digest?: string;
|
|
51
|
+
/** 首处理时间(RFC 3339)。 */
|
|
52
|
+
recorded_at: string;
|
|
53
|
+
/** retention 截止(RFC 3339);sweep 只清理 expires_at <= now 的记录。 */
|
|
54
|
+
expires_at: string;
|
|
55
|
+
}
|
|
56
|
+
export type IdempotencyDecision = {
|
|
57
|
+
status: "new";
|
|
58
|
+
key: string;
|
|
59
|
+
} | {
|
|
60
|
+
status: "replayed";
|
|
61
|
+
key: string;
|
|
62
|
+
record: IdempotencyRecord;
|
|
63
|
+
} | {
|
|
64
|
+
status: "conflict";
|
|
65
|
+
key: string;
|
|
66
|
+
record: IdempotencyRecord;
|
|
67
|
+
};
|
|
68
|
+
export interface IdempotencyCheckInput {
|
|
69
|
+
sender_identity: string;
|
|
70
|
+
message_id: string;
|
|
71
|
+
digest: string;
|
|
72
|
+
}
|
|
73
|
+
/** commit 的完整输入:除了持久化字段,还带 retention 计算所需的时限。 */
|
|
74
|
+
export interface IdempotencyCommitInput extends IdempotencyCheckInput {
|
|
75
|
+
negotiation_id: string;
|
|
76
|
+
outcome: IdempotencyRecord["outcome"];
|
|
77
|
+
ledger_event_id?: string;
|
|
78
|
+
ledger_event_digest?: string;
|
|
79
|
+
retention?: RetentionInput;
|
|
80
|
+
}
|
|
81
|
+
/** retention 时限提示;offer_valid_until / task_lifetime_until 均优先于 24h 地板。 */
|
|
82
|
+
export interface RetentionInput {
|
|
83
|
+
/** 仍有效的 offer 截止(RFC 3339),即 offer terms 的 valid_until。 */
|
|
84
|
+
offer_valid_until?: string;
|
|
85
|
+
/** A2A task 生命周期截止(RFC 3339)。 */
|
|
86
|
+
task_lifetime_until?: string;
|
|
87
|
+
}
|
|
88
|
+
/** 幂等键:null 字节分隔,避免 (a, b) 与 (ab, "") 之类碰撞。 */
|
|
89
|
+
export declare function idempotencyKey(senderIdentity: string, messageId: string): string;
|
|
90
|
+
/** 24 小时 retention 地板(基线 §17 / 子规范 §20.5)。 */
|
|
91
|
+
export declare const IDEMPOTENCY_FLOOR_MS: number;
|
|
92
|
+
/**
|
|
93
|
+
* 计算过期截止 = max(now + 24h, offer_valid_until, task_lifetime_until)。
|
|
94
|
+
* 无效/过去的时限自动被地板覆盖。
|
|
95
|
+
*/
|
|
96
|
+
export declare function computeRetentionDeadline(now: Date, input?: RetentionInput): Date;
|
|
97
|
+
/** same id + different digest → idempotency_conflict(§20.3 / §18 词表)。 */
|
|
98
|
+
export declare class IdempotencyConflictError extends Error {
|
|
99
|
+
readonly code: "idempotency_conflict";
|
|
100
|
+
readonly record: IdempotencyRecord;
|
|
101
|
+
constructor(record: IdempotencyRecord, digest: string);
|
|
102
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/** 幂等键:null 字节分隔,避免 (a, b) 与 (ab, "") 之类碰撞。 */
|
|
17
|
+
export function idempotencyKey(senderIdentity, messageId) {
|
|
18
|
+
return `${senderIdentity}\u0000${messageId}`;
|
|
19
|
+
}
|
|
20
|
+
/** 24 小时 retention 地板(基线 §17 / 子规范 §20.5)。 */
|
|
21
|
+
export const IDEMPOTENCY_FLOOR_MS = 24 * 60 * 60 * 1000;
|
|
22
|
+
/**
|
|
23
|
+
* 计算过期截止 = max(now + 24h, offer_valid_until, task_lifetime_until)。
|
|
24
|
+
* 无效/过去的时限自动被地板覆盖。
|
|
25
|
+
*/
|
|
26
|
+
export function computeRetentionDeadline(now, input = {}) {
|
|
27
|
+
let deadline = now.getTime() + IDEMPOTENCY_FLOOR_MS;
|
|
28
|
+
for (const iso of [input.offer_valid_until, input.task_lifetime_until]) {
|
|
29
|
+
if (iso === undefined)
|
|
30
|
+
continue;
|
|
31
|
+
const t = Date.parse(iso);
|
|
32
|
+
if (!Number.isNaN(t) && t > deadline)
|
|
33
|
+
deadline = t;
|
|
34
|
+
}
|
|
35
|
+
return new Date(deadline);
|
|
36
|
+
}
|
|
37
|
+
/** same id + different digest → idempotency_conflict(§20.3 / §18 词表)。 */
|
|
38
|
+
export class IdempotencyConflictError extends Error {
|
|
39
|
+
code = "idempotency_conflict";
|
|
40
|
+
record;
|
|
41
|
+
constructor(record, digest) {
|
|
42
|
+
super(`idempotency_conflict: (${record.sender_identity}, ${record.message_id}) already processed with digest ${record.digest}, got ${digest}`);
|
|
43
|
+
this.name = "IdempotencyConflictError";
|
|
44
|
+
this.record = record;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/negotiation/idempotency/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAiEH,+CAA+C;AAC/C,MAAM,UAAU,cAAc,CAAC,cAAsB,EAAE,SAAiB;IACtE,OAAO,GAAG,cAAc,SAAS,SAAS,EAAE,CAAC;AAC/C,CAAC;AAED,8CAA8C;AAC9C,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAExD;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAS,EAAE,QAAwB,EAAE;IAC5E,IAAI,QAAQ,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,oBAAoB,CAAC;IACpD,KAAK,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACvE,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ;YAAE,QAAQ,GAAG,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED,yEAAyE;AACzE,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,IAAI,GAAG,sBAA+B,CAAC;IACvC,MAAM,CAAoB;IACnC,YAAY,MAAyB,EAAE,MAAc;QACnD,KAAK,CACH,0BAA0B,MAAM,CAAC,eAAe,KAAK,MAAM,CAAC,UAAU,mCAAmC,MAAM,CAAC,MAAM,SAAS,MAAM,EAAE,CACxI,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/** RFC 8785 JCS canonical serialization of a JSON-compatible value. */
|
|
17
|
+
export declare function canonicalize(value: unknown): string;
|
|
18
|
+
/** sha256 hex of a UTF-8 string. */
|
|
19
|
+
export declare function sha256Hex(input: string): string;
|
|
20
|
+
/** Content-addressed digest of a structured value, `sha256:` prefixed. */
|
|
21
|
+
export declare function contentDigest(value: unknown): string;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* RFC 8785 JCS (JSON Canonicalization Scheme) — minimal deterministic
|
|
18
|
+
* serialization used for content addressing (docs §17 "Digest 与幂等").
|
|
19
|
+
*
|
|
20
|
+
* Pure and deterministic: no eval/exec, no random or time-dependent output.
|
|
21
|
+
* Equal inputs always serialize to the same byte string; object key order in
|
|
22
|
+
* the input is irrelevant (keys are sorted by UTF-16 code unit), which is
|
|
23
|
+
* what makes the digest stable across retries and restarts.
|
|
24
|
+
*
|
|
25
|
+
* The repo previously used a hand-rolled `stableStringify` (sorted keys, JSON
|
|
26
|
+
* values) for idempotency hashes. JCS is stricter about number serialization
|
|
27
|
+
* (`-0`, exponent normalization) and rejects non-finite numbers instead of
|
|
28
|
+
* silently hashing them. New content-addressed values (candidate_digest) MUST
|
|
29
|
+
* go through this module; the legacy helper is left untouched for v0.3 stores.
|
|
30
|
+
*/
|
|
31
|
+
import { createHash } from "node:crypto";
|
|
32
|
+
/**
|
|
33
|
+
* RFC 8785 §3.2.2.2 number serialization: shortest round-trip form with a
|
|
34
|
+
* normalized exponent (lowercase 'e', no leading '+' or exponent zeros), `-0`
|
|
35
|
+
* preserved, NaN/Infinity rejected.
|
|
36
|
+
*/
|
|
37
|
+
function canonicalNumber(value) {
|
|
38
|
+
if (!Number.isFinite(value)) {
|
|
39
|
+
throw new TypeError(`JCS: cannot canonicalize non-finite number ${value}`);
|
|
40
|
+
}
|
|
41
|
+
if (Object.is(value, -0))
|
|
42
|
+
return "-0";
|
|
43
|
+
// Number#toString produces the shortest round-trip representation, which
|
|
44
|
+
// RFC 8785 requires. Only the exponent needs normalization.
|
|
45
|
+
let serialized = String(value);
|
|
46
|
+
const exponent = /^(.+?)[eE]([+-]?)(\d+)$/.exec(serialized);
|
|
47
|
+
if (exponent !== null) {
|
|
48
|
+
const mantissa = exponent[1] ?? serialized;
|
|
49
|
+
const sign = exponent[2] === "-" ? "-" : "";
|
|
50
|
+
const digits = (exponent[3] ?? "").replace(/^0+/, "");
|
|
51
|
+
serialized = `${mantissa}e${sign}${digits === "" ? "0" : digits}`;
|
|
52
|
+
}
|
|
53
|
+
return serialized;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* RFC 8785 §3.2.2.1 字符串序列化:`"`/`\`/控制字符(JSON.stringify 已处理)
|
|
57
|
+
* + U+2028/U+2029(JSON.stringify 原样输出——RFC 8785 要求转义,否则与
|
|
58
|
+
* 按规范转义的实现产生不同 digest,跨实现互操作断裂)。
|
|
59
|
+
*/
|
|
60
|
+
function canonicalString(value) {
|
|
61
|
+
// 正则字面量用 \u2028/\u2029 Unicode 转义(非控制字符转义,eslint
|
|
62
|
+
// no-control-regex 不适用),匹配 U+2028(行分隔符)/ U+2029(段落分隔符)字符本身。
|
|
63
|
+
return JSON.stringify(value)
|
|
64
|
+
.replace(/\u2028/g, "\\u2028")
|
|
65
|
+
.replace(/\u2029/g, "\\u2029");
|
|
66
|
+
}
|
|
67
|
+
function canonicalValue(value) {
|
|
68
|
+
if (value === null)
|
|
69
|
+
return "null";
|
|
70
|
+
switch (typeof value) {
|
|
71
|
+
case "string":
|
|
72
|
+
return canonicalString(value);
|
|
73
|
+
case "boolean":
|
|
74
|
+
return value ? "true" : "false";
|
|
75
|
+
case "number":
|
|
76
|
+
return canonicalNumber(value);
|
|
77
|
+
case "object": {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
return `[${value
|
|
80
|
+
.map((element) => {
|
|
81
|
+
if (element === undefined) {
|
|
82
|
+
throw new TypeError("JCS: array elements must not be undefined");
|
|
83
|
+
}
|
|
84
|
+
return canonicalValue(element);
|
|
85
|
+
})
|
|
86
|
+
.join(",")}]`;
|
|
87
|
+
}
|
|
88
|
+
const record = value;
|
|
89
|
+
// Undefined-valued keys are optional fields and are skipped, matching
|
|
90
|
+
// the rest of the codebase; every other non-JSON value fails closed.
|
|
91
|
+
const keys = Object.keys(record)
|
|
92
|
+
.filter((key) => record[key] !== undefined)
|
|
93
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
94
|
+
return `{${keys.map((key) => `${canonicalString(key)}:${canonicalValue(record[key])}`).join(",")}}`;
|
|
95
|
+
}
|
|
96
|
+
default:
|
|
97
|
+
// functions, symbols, bigint: not part of the JSON data model — fail
|
|
98
|
+
// closed rather than producing a digest that hides the shape.
|
|
99
|
+
throw new TypeError(`JCS: cannot canonicalize ${typeof value}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** RFC 8785 JCS canonical serialization of a JSON-compatible value. */
|
|
103
|
+
export function canonicalize(value) {
|
|
104
|
+
return canonicalValue(value);
|
|
105
|
+
}
|
|
106
|
+
/** sha256 hex of a UTF-8 string. */
|
|
107
|
+
export function sha256Hex(input) {
|
|
108
|
+
return createHash("sha256").update(input, "utf8").digest("hex");
|
|
109
|
+
}
|
|
110
|
+
/** Content-addressed digest of a structured value, `sha256:` prefixed. */
|
|
111
|
+
export function contentDigest(value) {
|
|
112
|
+
return `sha256:${sha256Hex(canonicalize(value))}`;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=jcs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcs.js","sourceRoot":"","sources":["../../src/negotiation/jcs.ts"],"names":[],"mappings":"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"}
|