@7h3/protocol 0.1.2 → 0.5.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/.dockerignore +19 -0
- package/.github/dependabot.yml +32 -0
- package/.github/workflows/ci.yml +31 -0
- package/.github/workflows/publish.yml +59 -0
- package/.github/workflows/scorecard.yml +37 -0
- package/7h3.example.yaml +125 -0
- package/CHANGELOG.md +152 -0
- package/CONTRIBUTING.md +82 -0
- package/Dockerfile +73 -0
- package/GOVERNANCE.md +62 -0
- package/README.md +1317 -6
- package/SECURITY.md +70 -0
- package/bench-results/replay-cache-full-1777891033256.json +10 -0
- package/bench-results/replay-cache-full-1777896317488.json +10 -0
- package/bench-results/replay-cache-full-1777900993184.json +10 -0
- package/bench-results/replay-cache-full-1777901019285.json +10 -0
- package/bench-results/replay-cache-quick-1777870170126.json +10 -0
- package/bench-results/signature-profiles-quick-1775875160079.json +85 -0
- package/bench-results/signature-profiles-quick-1775983539716.json +85 -0
- package/bench-results/signature-profiles-quick-1776237913190.json +85 -0
- package/bench-results/wire-codecs-full-1777891019803.json +93 -0
- package/bench-results/wire-codecs-full-1777896260964.json +93 -0
- package/bench-results/wire-codecs-full-1777901004247.json +93 -0
- package/bench-results/wire-codecs-quick-1775972879056.json +93 -0
- package/bench-results/wire-codecs-quick-1775983541111.json +93 -0
- package/bench-results/wire-codecs-quick-1776237914299.json +93 -0
- package/bench-results/wire-codecs-quick-1777841285236.json +93 -0
- package/bench-results/wire-codecs-quick-1777841321772.json +93 -0
- package/bench-results/wire-codecs-quick-1777841330408.json +93 -0
- package/bench-results/wire-codecs-quick-1777852886082.json +93 -0
- package/bench-results/wire-codecs-quick-1777852988773.json +93 -0
- package/bench-results/wire-codecs-quick-1777870188095.json +93 -0
- package/bench-results/wire-codecs-quick-1777870263918.json +93 -0
- package/bench-results/wire-codecs-quick-1777870455034.json +93 -0
- package/bench-results/wire-codecs-quick-1778816163081.json +93 -0
- package/bench-results/wire-codecs-quick-1778843936130.json +93 -0
- package/bin/7h3.ts +406 -0
- package/conformance/7h3_v0_1.json +77 -0
- package/conformance/7h3_v0_1_binary.json +20 -0
- package/conformance/aip_v0_1_binary.json +20 -0
- package/docker-compose.yaml +77 -0
- package/docs/ADOPTION_PLAN.md +120 -0
- package/docs/AGENTS.md +77 -0
- package/docs/AIP_RFC_v0.1.md +97 -0
- package/docs/AI_DECISION_CARD.md +122 -0
- package/docs/AI_RUNTIME_POLICY.json +126 -0
- package/docs/AI_RUNTIME_POLICY.yaml +110 -0
- package/docs/BACKPRESSURE_TUNING.md +65 -0
- package/docs/BENCHMARK_CLAIM_MATRIX.md +42 -0
- package/docs/BENCHMARK_REPORT_TEMPLATE.md +169 -0
- package/docs/BINARY_CODEC_BENCH.md +23 -0
- package/docs/CLEAN_CLONE_RUNBOOK.md +36 -0
- package/docs/CLOCK_SKEW_POLICY.md +30 -0
- package/docs/DISTRIBUTED_REPLAY.md +142 -0
- package/docs/FUZZ_CAMPAIGN.md +121 -0
- package/docs/GATEWAY.md +195 -0
- package/docs/KEY_MANAGEMENT_POLICY.md +53 -0
- package/docs/KEY_REVOCATION.md +69 -0
- package/docs/MCP_WRAPPER.md +159 -0
- package/docs/MIGRATION_GUIDE.md +40 -0
- package/docs/OPERATORS.md +184 -0
- package/docs/PERF_REGRESSION_POLICY.md +34 -0
- package/docs/PROJECT_EXAMINATION_2026-05-31.md +219 -0
- package/docs/RELEASE_BENCHMARK_REPORT_2026-05-15.md +135 -0
- package/docs/RELEASE_GATE.md +25 -0
- package/docs/RELEASE_NOTES_v0.1.0.md +54 -0
- package/docs/SECURITY_REVIEW_2026-06-05.md +165 -0
- package/docs/TELEMETRY.md +41 -0
- package/docs/THREAT_MODEL.md +89 -0
- package/docs/VERSIONING_POLICY.md +30 -0
- package/docs/assets/banner-github.png +0 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/banner.svg +123 -0
- package/eslint.config.js +15 -0
- package/fuzz/ts/harness-decode.ts +136 -0
- package/fuzz/ts/harness-verify.ts +121 -0
- package/fuzz/ts/run.ts +35 -0
- package/mcp-server/README.md +38 -0
- package/mcp-server/package-lock.json +1187 -0
- package/mcp-server/package.json +35 -0
- package/mcp-server/src/index.ts +236 -0
- package/mcp-server/tsconfig.json +14 -0
- package/package.json +121 -13
- package/scripts/aip-framework-quickstart.ts +110 -0
- package/scripts/aip-mcp-gateway.ts +38 -0
- package/scripts/aip-mcp-wrap-demo.ts +72 -0
- package/scripts/aip-quickstart.ts +60 -0
- package/scripts/bench-diff.ts +118 -0
- package/scripts/bench-protocol-e2e.ts +937 -0
- package/scripts/bench-protocol-openloop.ts +1397 -0
- package/scripts/bench-replay-cache.ts +76 -0
- package/scripts/bench-signature-profiles.ts +180 -0
- package/scripts/bench-wire-codecs.ts +161 -0
- package/scripts/build-binary-conformance.ts +36 -0
- package/scripts/build-release-dashboard.ts +175 -0
- package/scripts/canary-rollout.ts +38 -0
- package/scripts/mcpGatewayCli.test.ts +116 -0
- package/scripts/prepare-aip-package.ts +88 -0
- package/scripts/regen-conformance-sigs.ts +18 -0
- package/scripts/release-gate.ts +19 -0
- package/scripts/validate-runtime-policy.ts +18 -0
- package/sdk/browser/index.test.ts +162 -0
- package/sdk/browser/index.ts +257 -0
- package/sdk/browser/package.json +13 -0
- package/sdk/go/cbor.go +551 -0
- package/sdk/go/cbor_test.go +232 -0
- package/sdk/go/encryption.go +280 -0
- package/sdk/go/encryption_test.go +318 -0
- package/sdk/go/go.mod +7 -0
- package/sdk/go/go.sum +4 -0
- package/sdk/go/http.go +135 -0
- package/sdk/go/protocol.go +324 -0
- package/sdk/go/protocol_test.go +334 -0
- package/sdk/go/replay.go +121 -0
- package/sdk/go/replay_test.go +149 -0
- package/sdk/go/webhook.go +136 -0
- package/sdk/pq/package-lock.json +1358 -0
- package/sdk/pq/package.json +42 -0
- package/sdk/pq/src/index.test.ts +143 -0
- package/sdk/pq/src/index.ts +166 -0
- package/sdk/pq/tsconfig.json +14 -0
- package/sdk/pq/vitest.config.ts +7 -0
- package/sdk/python/README.md +18 -0
- package/sdk/python/protocol_7h3/__init__.py +46 -0
- package/sdk/python/protocol_7h3/encryption.py +252 -0
- package/sdk/python/protocol_7h3/http.py +212 -0
- package/sdk/python/protocol_7h3/keys.py +149 -0
- package/sdk/python/protocol_7h3/pq.py +244 -0
- package/sdk/python/protocol_7h3/protocol.py +525 -0
- package/sdk/python/protocol_7h3/queue.py +118 -0
- package/sdk/python/protocol_7h3/replay.py +98 -0
- package/sdk/python/protocol_7h3/webhook.py +116 -0
- package/sdk/python/pyproject.toml +40 -0
- package/sdk/python/tests/test_conformance.py +110 -0
- package/sdk/python/tests/test_encryption.py +206 -0
- package/sdk/python/tests/test_http.py +305 -0
- package/sdk/python/tests/test_keys.py +417 -0
- package/sdk/python/tests/test_queue.py +120 -0
- package/sdk/python/tests/test_webhook.py +345 -0
- package/sdk/rust/Cargo.lock +371 -0
- package/sdk/rust/Cargo.toml +25 -0
- package/sdk/rust/README.md +31 -0
- package/sdk/rust/fuzz/Cargo.toml +29 -0
- package/sdk/rust/fuzz/fuzz_targets/fuzz_canonicalize.rs +46 -0
- package/sdk/rust/fuzz/fuzz_targets/fuzz_decode.rs +11 -0
- package/sdk/rust/src/bin/aip_mcp_gateway.rs +59 -0
- package/sdk/rust/src/http.rs +145 -0
- package/sdk/rust/src/keys.rs +161 -0
- package/sdk/rust/src/lib.rs +688 -0
- package/sdk/rust/src/queue.rs +79 -0
- package/sdk/rust/src/webhook.rs +86 -0
- package/sdk/rust/tests/conformance.rs +148 -0
- package/sdk/rust/tests/gateway.rs +130 -0
- package/sdk/rust/tests/http_webhook_queue.rs +201 -0
- package/sdk/rust/tests/keys.rs +189 -0
- package/sdk/threshold/index.d.ts +68 -0
- package/sdk/threshold/index.d.ts.map +1 -0
- package/sdk/threshold/index.js +254 -0
- package/sdk/threshold/package-lock.json +1361 -0
- package/sdk/threshold/package.json +39 -0
- package/sdk/threshold/src/index.d.ts +68 -0
- package/sdk/threshold/src/index.d.ts.map +1 -0
- package/sdk/threshold/src/index.js +254 -0
- package/sdk/threshold/src/index.test.ts +238 -0
- package/sdk/threshold/src/index.ts +355 -0
- package/sdk/threshold/tsconfig.json +19 -0
- package/sdk/threshold/vitest.config.ts +12 -0
- package/src/agentAdapter.test.ts +48 -0
- package/src/agentAdapter.ts +56 -0
- package/src/auditLog.test.ts +145 -0
- package/src/auditLog.ts +147 -0
- package/src/capability.test.ts +504 -0
- package/src/capability.ts +380 -0
- package/src/cborCodec.test.ts +263 -0
- package/src/cborCodec.ts +339 -0
- package/src/conformance.test.ts +136 -0
- package/src/conformanceVectors.ts +99 -0
- package/src/encryption.test.ts +206 -0
- package/src/encryption.ts +245 -0
- package/src/envelopeCbor.ts +140 -0
- package/src/frameworkAdapters.test.ts +290 -0
- package/src/frameworkAdapters.ts +261 -0
- package/src/gateway.test.ts +343 -0
- package/src/gateway.ts +246 -0
- package/src/grpcBinding.test.ts +211 -0
- package/src/grpcBinding.ts +103 -0
- package/src/httpBinding.test.ts +376 -0
- package/src/httpBinding.ts +189 -0
- package/src/index.ts +39 -0
- package/src/keyInfra.test.ts +278 -0
- package/src/keyInfra.ts +228 -0
- package/src/keyRegistry.ts +59 -0
- package/src/keyRotation.test.ts +78 -0
- package/src/keyRotation.ts +72 -0
- package/src/mcpGateway.test.ts +129 -0
- package/src/mcpGateway.ts +250 -0
- package/src/mcpTransports.test.ts +92 -0
- package/src/mcpTransports.ts +169 -0
- package/src/mcpWrapper.test.ts +179 -0
- package/src/mcpWrapper.ts +206 -0
- package/src/otel.ts +136 -0
- package/src/policyEnforcer.test.ts +99 -0
- package/src/policyEnforcer.ts +169 -0
- package/src/policyTelemetryFeedback.test.ts +25 -0
- package/src/policyTelemetryFeedback.ts +38 -0
- package/src/protocol.bench.ts +37 -0
- package/{protocol.d.ts → src/protocol.d.ts} +2 -1
- package/src/protocol.d.ts.map +1 -0
- package/src/protocol.js +294 -0
- package/src/protocol.test.ts +155 -0
- package/src/protocol.ts +414 -0
- package/src/protocolAgent.test.ts +105 -0
- package/src/protocolAgent.ts +169 -0
- package/src/protocolBinary.test.ts +165 -0
- package/src/protocolBinary.ts +312 -0
- package/src/protocolCapabilities.ts +70 -0
- package/src/protocolFuzz.advanced.test.ts +235 -0
- package/src/protocolFuzz.test.ts +111 -0
- package/src/protocolNegative.test.ts +97 -0
- package/src/protocolReplay.test.ts +71 -0
- package/src/protocolReplay.ts +194 -0
- package/src/protocolTransport.test.ts +556 -0
- package/src/protocolTransport.ts +483 -0
- package/src/queueBinding.test.ts +130 -0
- package/src/queueBinding.ts +102 -0
- package/src/rateLimiter.test.ts +96 -0
- package/src/rateLimiter.ts +46 -0
- package/src/redisClient.ts +140 -0
- package/src/redisIntegration.test.ts +134 -0
- package/src/replayStores.test.ts +273 -0
- package/src/replayStores.ts +215 -0
- package/src/revocation.test.ts +98 -0
- package/src/revocation.ts +0 -0
- package/src/routePolicy.test.ts +87 -0
- package/src/routePolicy.ts +72 -0
- package/src/runtimePolicy.test.ts +49 -0
- package/src/runtimePolicy.ts +81 -0
- package/src/runtimePolicyManager.test.ts +29 -0
- package/src/runtimePolicyManager.ts +50 -0
- package/src/runtimePolicyPresets.ts +43 -0
- package/src/signedResponse.test.ts +111 -0
- package/src/signedResponse.ts +83 -0
- package/src/stream.test.ts +254 -0
- package/src/stream.ts +417 -0
- package/src/telemetry.test.ts +251 -0
- package/src/telemetry.ts +299 -0
- package/src/webhookBinding.test.ts +144 -0
- package/src/webhookBinding.ts +115 -0
- package/src/wsBinding.test.ts +221 -0
- package/src/wsBinding.ts +200 -0
- package/tsconfig.json +15 -0
- package/tsconfig.lib.json +23 -0
- package/vite.lib.config.ts +16 -0
- package/vitest.config.ts +11 -0
- package/agentAdapter.d.ts +0 -26
- package/conformanceVectors.d.ts +0 -20
- package/frameworkAdapters.d.ts +0 -72
- package/index.d.ts +0 -20
- package/index.js +0 -1702
- package/keyRotation.d.ts +0 -20
- package/mcpGateway.d.ts +0 -37
- package/mcpTransports.d.ts +0 -62
- package/mcpWrapper.d.ts +0 -83
- package/policyEnforcer.d.ts +0 -50
- package/policyTelemetryFeedback.d.ts +0 -11
- package/protocolAgent.d.ts +0 -58
- package/protocolBinary.d.ts +0 -8
- package/protocolCapabilities.d.ts +0 -24
- package/protocolReplay.d.ts +0 -35
- package/protocolTransport.d.ts +0 -73
- package/redisClient.d.ts +0 -49
- package/replayStores.d.ts +0 -32
- package/revocation.d.ts +0 -71
- package/runtimePolicy.d.ts +0 -24
- package/runtimePolicyManager.d.ts +0 -15
- package/runtimePolicyPresets.d.ts +0 -11
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
signCanonicalPayloadEd25519,
|
|
3
|
+
verifyCanonicalPayloadEd25519,
|
|
4
|
+
signCanonicalPayloadHmac,
|
|
5
|
+
verifyCanonicalPayloadHmac,
|
|
6
|
+
generateEd25519KeypairBase64Url,
|
|
7
|
+
} from './protocol'
|
|
8
|
+
|
|
9
|
+
export const WEBHOOK_SIG_HEADER = 'x-7h3-sig'
|
|
10
|
+
export const WEBHOOK_TS_HEADER = 'x-7h3-ts'
|
|
11
|
+
export const WEBHOOK_DEFAULT_TTL_MS = 300_000 // 5 minutes
|
|
12
|
+
|
|
13
|
+
// What gets signed: "${timestampMs}.${rawBody}" — binds time AND content
|
|
14
|
+
function webhookSigningPayload(timestampMs: number, body: string): string {
|
|
15
|
+
return `${timestampMs}.${body}`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface WebhookSignOptions {
|
|
19
|
+
privateKey: string // Ed25519 PKCS8 base64url
|
|
20
|
+
ttlMs?: number // default 5 min
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface WebhookSignHmacOptions {
|
|
24
|
+
secret: string
|
|
25
|
+
ttlMs?: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface WebhookVerifyOptions {
|
|
29
|
+
publicKey: string // Ed25519 SPKI base64url
|
|
30
|
+
maxAgeMs?: number // default 5 min
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface WebhookVerifyHmacOptions {
|
|
34
|
+
secret: string
|
|
35
|
+
maxAgeMs?: number
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface WebhookHeaders {
|
|
39
|
+
[WEBHOOK_SIG_HEADER]: string
|
|
40
|
+
[WEBHOOK_TS_HEADER]: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Sign a webhook payload with Ed25519
|
|
44
|
+
export async function signWebhook(
|
|
45
|
+
payload: string | Uint8Array,
|
|
46
|
+
opts: WebhookSignOptions
|
|
47
|
+
): Promise<WebhookHeaders> {
|
|
48
|
+
const body = typeof payload === 'string' ? payload : new TextDecoder().decode(payload)
|
|
49
|
+
const timestampMs = Date.now()
|
|
50
|
+
const signingPayload = webhookSigningPayload(timestampMs, body)
|
|
51
|
+
const sig = await signCanonicalPayloadEd25519(signingPayload, opts.privateKey)
|
|
52
|
+
return { [WEBHOOK_SIG_HEADER]: sig, [WEBHOOK_TS_HEADER]: String(timestampMs) }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Sign with HMAC shared secret
|
|
56
|
+
export async function signWebhookHmac(
|
|
57
|
+
payload: string | Uint8Array,
|
|
58
|
+
opts: WebhookSignHmacOptions
|
|
59
|
+
): Promise<WebhookHeaders> {
|
|
60
|
+
const body = typeof payload === 'string' ? payload : new TextDecoder().decode(payload)
|
|
61
|
+
const timestampMs = Date.now()
|
|
62
|
+
const signingPayload = webhookSigningPayload(timestampMs, body)
|
|
63
|
+
const sig = await signCanonicalPayloadHmac(signingPayload, opts.secret)
|
|
64
|
+
return { [WEBHOOK_SIG_HEADER]: sig, [WEBHOOK_TS_HEADER]: String(timestampMs) }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Verify Ed25519 webhook signature
|
|
68
|
+
export async function verifyWebhook(
|
|
69
|
+
payload: string | Uint8Array,
|
|
70
|
+
headers: WebhookHeaders | Record<string, string>,
|
|
71
|
+
opts: WebhookVerifyOptions
|
|
72
|
+
): Promise<boolean> {
|
|
73
|
+
const body = typeof payload === 'string' ? payload : new TextDecoder().decode(payload)
|
|
74
|
+
const sig = headers[WEBHOOK_SIG_HEADER]
|
|
75
|
+
const tsStr = headers[WEBHOOK_TS_HEADER]
|
|
76
|
+
if (!sig || !tsStr) return false
|
|
77
|
+
const ts = Number(tsStr)
|
|
78
|
+
if (!Number.isFinite(ts)) return false
|
|
79
|
+
const maxAge = opts.maxAgeMs ?? WEBHOOK_DEFAULT_TTL_MS
|
|
80
|
+
if (Date.now() - ts > maxAge) return false
|
|
81
|
+
const signingPayload = webhookSigningPayload(ts, body)
|
|
82
|
+
return verifyCanonicalPayloadEd25519(signingPayload, sig, opts.publicKey)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Verify HMAC webhook signature
|
|
86
|
+
export async function verifyWebhookHmac(
|
|
87
|
+
payload: string | Uint8Array,
|
|
88
|
+
headers: WebhookHeaders | Record<string, string>,
|
|
89
|
+
opts: WebhookVerifyHmacOptions
|
|
90
|
+
): Promise<boolean> {
|
|
91
|
+
const body = typeof payload === 'string' ? payload : new TextDecoder().decode(payload)
|
|
92
|
+
const sig = headers[WEBHOOK_SIG_HEADER]
|
|
93
|
+
const tsStr = headers[WEBHOOK_TS_HEADER]
|
|
94
|
+
if (!sig || !tsStr) return false
|
|
95
|
+
const ts = Number(tsStr)
|
|
96
|
+
if (!Number.isFinite(ts)) return false
|
|
97
|
+
const maxAge = opts.maxAgeMs ?? WEBHOOK_DEFAULT_TTL_MS
|
|
98
|
+
if (Date.now() - ts > maxAge) return false
|
|
99
|
+
const signingPayload = webhookSigningPayload(ts, body)
|
|
100
|
+
return verifyCanonicalPayloadHmac(signingPayload, sig, opts.secret)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Parse and verify in one call, throws on failure
|
|
104
|
+
export async function consumeWebhook<T = unknown>(
|
|
105
|
+
payload: string,
|
|
106
|
+
headers: Record<string, string>,
|
|
107
|
+
opts: WebhookVerifyOptions
|
|
108
|
+
): Promise<T> {
|
|
109
|
+
const valid = await verifyWebhook(payload, headers, opts)
|
|
110
|
+
if (!valid) throw new Error('7h3: webhook signature verification failed')
|
|
111
|
+
return JSON.parse(payload) as T
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Re-export key generation for convenience
|
|
115
|
+
export { generateEd25519KeypairBase64Url }
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { wrapWebSocket, generateEd25519KeypairBase64Url, type WebSocketLike } from './wsBinding'
|
|
3
|
+
import { signEnvelopeEd25519, createEnvelope, type ProtocolEnvelope } from './protocol'
|
|
4
|
+
import { createStaticKeyRegistry } from './keyRegistry'
|
|
5
|
+
|
|
6
|
+
// Mock WebSocket class that buffers sent messages and lets you inject received messages
|
|
7
|
+
class MockWebSocket implements WebSocketLike {
|
|
8
|
+
public sent: string[] = []
|
|
9
|
+
private messageHandlers: Array<(e: { data: string }) => void> = []
|
|
10
|
+
private closeHandlers: Array<() => void> = []
|
|
11
|
+
readyState = 1
|
|
12
|
+
|
|
13
|
+
send(data: string): void {
|
|
14
|
+
this.sent.push(data)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
addEventListener(event: string, handler: (...args: any[]) => void): void {
|
|
18
|
+
if (event === 'message') {
|
|
19
|
+
this.messageHandlers.push(handler as (e: { data: string }) => void)
|
|
20
|
+
} else if (event === 'close') {
|
|
21
|
+
this.closeHandlers.push(handler as () => void)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
removeEventListener(event: string, handler: (...args: unknown[]) => void): void {
|
|
26
|
+
if (event === 'message') {
|
|
27
|
+
const idx = this.messageHandlers.indexOf(handler as any)
|
|
28
|
+
if (idx !== -1) this.messageHandlers.splice(idx, 1)
|
|
29
|
+
} else if (event === 'close') {
|
|
30
|
+
const idx = this.closeHandlers.indexOf(handler as any)
|
|
31
|
+
if (idx !== -1) this.closeHandlers.splice(idx, 1)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Inject a received message
|
|
36
|
+
receive(data: string): void {
|
|
37
|
+
for (const h of this.messageHandlers) h({ data })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
close(): void {
|
|
41
|
+
for (const h of this.closeHandlers) h()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('wrapWebSocket', () => {
|
|
46
|
+
it('send() produces a signed JSON frame', async () => {
|
|
47
|
+
const keypair = await generateEd25519KeypairBase64Url()
|
|
48
|
+
const ws = new MockWebSocket()
|
|
49
|
+
const registry = createStaticKeyRegistry({ 'agent-A': keypair.publicKey })
|
|
50
|
+
|
|
51
|
+
const pws = wrapWebSocket(ws, {
|
|
52
|
+
privateKey: keypair.privateKey,
|
|
53
|
+
sender: 'agent-A',
|
|
54
|
+
keyRegistry: registry,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
await pws.send({ hello: 'world' })
|
|
58
|
+
|
|
59
|
+
expect(ws.sent).toHaveLength(1)
|
|
60
|
+
const frame = JSON.parse(ws.sent[0]) as ProtocolEnvelope
|
|
61
|
+
expect(frame.header.sender).toBe('agent-A')
|
|
62
|
+
expect(frame.signature).toBeDefined()
|
|
63
|
+
expect(frame.signature?.alg).toBe('ED25519')
|
|
64
|
+
expect(frame.body.intent).toBe('TASK')
|
|
65
|
+
expect(frame.body.content).toBe(JSON.stringify({ hello: 'world' }))
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('incoming signed frame calls onMessage handler', async () => {
|
|
69
|
+
const keypair = await generateEd25519KeypairBase64Url()
|
|
70
|
+
const ws = new MockWebSocket()
|
|
71
|
+
const registry = createStaticKeyRegistry({ 'agent-B': keypair.publicKey })
|
|
72
|
+
|
|
73
|
+
const pws = wrapWebSocket(ws, {
|
|
74
|
+
privateKey: keypair.privateKey,
|
|
75
|
+
sender: 'agent-A',
|
|
76
|
+
keyRegistry: registry,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const received: Array<{ payload: unknown; envelope: ProtocolEnvelope }> = []
|
|
80
|
+
pws.onMessage((payload, envelope) => received.push({ payload, envelope }))
|
|
81
|
+
|
|
82
|
+
// Create a valid signed frame from agent-B
|
|
83
|
+
const envelope = createEnvelope({
|
|
84
|
+
sender: 'agent-B',
|
|
85
|
+
intent: 'TASK',
|
|
86
|
+
content: JSON.stringify({ ping: true }),
|
|
87
|
+
ttlMs: 30_000,
|
|
88
|
+
})
|
|
89
|
+
const signed = await signEnvelopeEd25519(envelope, keypair.privateKey)
|
|
90
|
+
|
|
91
|
+
// Wait for async message processing
|
|
92
|
+
await new Promise<void>(resolve => {
|
|
93
|
+
pws.onMessage(() => resolve())
|
|
94
|
+
ws.receive(JSON.stringify(signed))
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
expect(received).toHaveLength(1)
|
|
98
|
+
expect(received[0].payload).toEqual({ ping: true })
|
|
99
|
+
expect(received[0].envelope.header.sender).toBe('agent-B')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('tampered frame calls onVerifyFail', async () => {
|
|
103
|
+
const keypair = await generateEd25519KeypairBase64Url()
|
|
104
|
+
const ws = new MockWebSocket()
|
|
105
|
+
const registry = createStaticKeyRegistry({ 'agent-B': keypair.publicKey })
|
|
106
|
+
|
|
107
|
+
const pws = wrapWebSocket(ws, {
|
|
108
|
+
privateKey: keypair.privateKey,
|
|
109
|
+
sender: 'agent-A',
|
|
110
|
+
keyRegistry: registry,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const errors: Error[] = []
|
|
114
|
+
pws.onVerifyFail((err) => errors.push(err))
|
|
115
|
+
|
|
116
|
+
// Create a valid signed frame, then tamper with body content
|
|
117
|
+
const envelope = createEnvelope({
|
|
118
|
+
sender: 'agent-B',
|
|
119
|
+
intent: 'TASK',
|
|
120
|
+
content: 'original content',
|
|
121
|
+
ttlMs: 30_000,
|
|
122
|
+
})
|
|
123
|
+
const signed = await signEnvelopeEd25519(envelope, keypair.privateKey)
|
|
124
|
+
// Tamper with content after signing
|
|
125
|
+
const tampered = { ...signed, body: { ...signed.body, content: 'tampered content' } }
|
|
126
|
+
|
|
127
|
+
await new Promise<void>(resolve => {
|
|
128
|
+
pws.onVerifyFail(() => resolve())
|
|
129
|
+
ws.receive(JSON.stringify(tampered))
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
expect(errors).toHaveLength(1)
|
|
133
|
+
expect(errors[0].message).toContain('invalid signature')
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('unknown sender calls onVerifyFail', async () => {
|
|
137
|
+
const keypair = await generateEd25519KeypairBase64Url()
|
|
138
|
+
const ws = new MockWebSocket()
|
|
139
|
+
// Registry has no entry for 'unknown-agent'
|
|
140
|
+
const registry = createStaticKeyRegistry({})
|
|
141
|
+
|
|
142
|
+
const pws = wrapWebSocket(ws, {
|
|
143
|
+
privateKey: keypair.privateKey,
|
|
144
|
+
sender: 'agent-A',
|
|
145
|
+
keyRegistry: registry,
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const errors: Error[] = []
|
|
149
|
+
pws.onVerifyFail((err) => errors.push(err))
|
|
150
|
+
|
|
151
|
+
const envelope = createEnvelope({
|
|
152
|
+
sender: 'unknown-agent',
|
|
153
|
+
intent: 'TASK',
|
|
154
|
+
content: 'hello',
|
|
155
|
+
ttlMs: 30_000,
|
|
156
|
+
})
|
|
157
|
+
const signed = await signEnvelopeEd25519(envelope, keypair.privateKey)
|
|
158
|
+
|
|
159
|
+
await new Promise<void>(resolve => {
|
|
160
|
+
pws.onVerifyFail(() => resolve())
|
|
161
|
+
ws.receive(JSON.stringify(signed))
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
expect(errors).toHaveLength(1)
|
|
165
|
+
expect(errors[0].message).toContain('unknown sender')
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('malformed JSON calls onVerifyFail', async () => {
|
|
169
|
+
const keypair = await generateEd25519KeypairBase64Url()
|
|
170
|
+
const ws = new MockWebSocket()
|
|
171
|
+
const registry = createStaticKeyRegistry({})
|
|
172
|
+
|
|
173
|
+
const pws = wrapWebSocket(ws, {
|
|
174
|
+
privateKey: keypair.privateKey,
|
|
175
|
+
sender: 'agent-A',
|
|
176
|
+
keyRegistry: registry,
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const errors: Error[] = []
|
|
180
|
+
pws.onVerifyFail((err) => errors.push(err))
|
|
181
|
+
|
|
182
|
+
await new Promise<void>(resolve => {
|
|
183
|
+
pws.onVerifyFail(() => resolve())
|
|
184
|
+
ws.receive('this is not valid JSON {{{')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
expect(errors).toHaveLength(1)
|
|
188
|
+
expect(errors[0].message).toContain('malformed frame')
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('seq increments on each send', async () => {
|
|
192
|
+
const keypair = await generateEd25519KeypairBase64Url()
|
|
193
|
+
const ws = new MockWebSocket()
|
|
194
|
+
const registry = createStaticKeyRegistry({ 'agent-A': keypair.publicKey })
|
|
195
|
+
|
|
196
|
+
const pws = wrapWebSocket(ws, {
|
|
197
|
+
privateKey: keypair.privateKey,
|
|
198
|
+
sender: 'agent-A',
|
|
199
|
+
keyRegistry: registry,
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
expect(pws.seq).toBe(0)
|
|
203
|
+
|
|
204
|
+
await pws.send('first')
|
|
205
|
+
expect(pws.seq).toBe(1)
|
|
206
|
+
|
|
207
|
+
await pws.send('second')
|
|
208
|
+
expect(pws.seq).toBe(2)
|
|
209
|
+
|
|
210
|
+
await pws.send('third')
|
|
211
|
+
expect(pws.seq).toBe(3)
|
|
212
|
+
|
|
213
|
+
// Verify correlationId carries the seq number
|
|
214
|
+
const frame1 = JSON.parse(ws.sent[0]) as ProtocolEnvelope
|
|
215
|
+
const frame2 = JSON.parse(ws.sent[1]) as ProtocolEnvelope
|
|
216
|
+
const frame3 = JSON.parse(ws.sent[2]) as ProtocolEnvelope
|
|
217
|
+
expect(frame1.body.correlationId).toBe('1')
|
|
218
|
+
expect(frame2.body.correlationId).toBe('2')
|
|
219
|
+
expect(frame3.body.correlationId).toBe('3')
|
|
220
|
+
})
|
|
221
|
+
})
|
package/src/wsBinding.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
signEnvelopeEd25519, verifyEnvelopeEd25519,
|
|
3
|
+
createEnvelope, validateEnvelope,
|
|
4
|
+
generateEd25519KeypairBase64Url, type ProtocolEnvelope
|
|
5
|
+
} from './protocol'
|
|
6
|
+
import type { KeyRegistry } from './keyRegistry'
|
|
7
|
+
import {
|
|
8
|
+
SignedStreamWriter,
|
|
9
|
+
verifyStream,
|
|
10
|
+
decodeStreamChunk,
|
|
11
|
+
encodeStreamChunk,
|
|
12
|
+
type StreamSignerOpts,
|
|
13
|
+
type StreamVerifierOpts,
|
|
14
|
+
type StreamVerifyResult,
|
|
15
|
+
type StreamChunk,
|
|
16
|
+
} from './stream'
|
|
17
|
+
|
|
18
|
+
export { type KeyRegistry, generateEd25519KeypairBase64Url }
|
|
19
|
+
export type { StreamSignerOpts, StreamVerifierOpts, StreamVerifyResult, StreamChunk }
|
|
20
|
+
|
|
21
|
+
// Minimal WebSocket interface (works with browser WebSocket, ws library, etc.)
|
|
22
|
+
export interface WebSocketLike {
|
|
23
|
+
send(data: string): void
|
|
24
|
+
addEventListener(event: 'message', handler: (e: { data: string | Buffer }) => void): void
|
|
25
|
+
addEventListener(event: 'close', handler: () => void): void
|
|
26
|
+
removeEventListener(event: string, handler: (...args: unknown[]) => void): void
|
|
27
|
+
readyState?: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface WsBindingOptions {
|
|
31
|
+
privateKey: string
|
|
32
|
+
sender: string
|
|
33
|
+
recipient?: string
|
|
34
|
+
keyRegistry: KeyRegistry // to look up peer public keys by sender ID
|
|
35
|
+
ttlMs?: number // per-frame TTL, default 30_000
|
|
36
|
+
onVerifyFail?: (err: Error, rawData: string) => void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ProtectedWebSocket {
|
|
40
|
+
// Send a payload — automatically signs it
|
|
41
|
+
send(payload: unknown): Promise<void>
|
|
42
|
+
// Register handler for verified incoming messages
|
|
43
|
+
onMessage(handler: (payload: unknown, envelope: ProtocolEnvelope) => void): void
|
|
44
|
+
// Register handler for verify failures (optional)
|
|
45
|
+
onVerifyFail(handler: (err: Error, rawData: string) => void): void
|
|
46
|
+
// Sequence number of last sent message
|
|
47
|
+
readonly seq: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function wrapWebSocket(ws: WebSocketLike, opts: WsBindingOptions): ProtectedWebSocket {
|
|
51
|
+
let seq = 0
|
|
52
|
+
const messageHandlers: Array<(payload: unknown, envelope: ProtocolEnvelope) => void> = []
|
|
53
|
+
const failHandlers: Array<(err: Error, rawData: string) => void> = []
|
|
54
|
+
|
|
55
|
+
function fireVerifyFail(err: Error, raw: string) {
|
|
56
|
+
opts.onVerifyFail?.(err, raw)
|
|
57
|
+
for (const h of failHandlers) h(err, raw)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Listen for incoming frames
|
|
61
|
+
const messageListener = async (e: { data: string | Buffer }) => {
|
|
62
|
+
const raw = typeof e.data === 'string' ? e.data : e.data.toString('utf8')
|
|
63
|
+
let envelope: ProtocolEnvelope
|
|
64
|
+
try { envelope = JSON.parse(raw) as ProtocolEnvelope }
|
|
65
|
+
catch (err) { fireVerifyFail(new Error('malformed frame'), raw); return }
|
|
66
|
+
|
|
67
|
+
const sender = envelope?.header?.sender
|
|
68
|
+
if (!sender) { fireVerifyFail(new Error('missing sender'), raw); return }
|
|
69
|
+
|
|
70
|
+
const publicKey = await opts.keyRegistry.getPublicKey(sender)
|
|
71
|
+
if (!publicKey) { fireVerifyFail(new Error(`unknown sender: ${sender}`), raw); return }
|
|
72
|
+
|
|
73
|
+
const valid = await verifyEnvelopeEd25519(envelope, publicKey).catch(() => false)
|
|
74
|
+
if (!valid) { fireVerifyFail(new Error('invalid signature'), raw); return }
|
|
75
|
+
|
|
76
|
+
const diags = validateEnvelope(envelope)
|
|
77
|
+
if (diags.some(d => d.level === 'error')) {
|
|
78
|
+
fireVerifyFail(new Error(`envelope invalid: ${diags.map(d => d.message).join('; ')}`), raw)
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let payload: unknown = envelope.body.content
|
|
83
|
+
try { payload = JSON.parse(envelope.body.content) } catch { /* keep as string */ }
|
|
84
|
+
for (const h of messageHandlers) h(payload, envelope)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
ws.addEventListener('message', messageListener as any)
|
|
88
|
+
ws.addEventListener('close', () => {
|
|
89
|
+
ws.removeEventListener('message', messageListener as any)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
get seq() { return seq },
|
|
94
|
+
async send(payload: unknown): Promise<void> {
|
|
95
|
+
const content = typeof payload === 'string' ? payload : JSON.stringify(payload)
|
|
96
|
+
const envelope = createEnvelope({
|
|
97
|
+
sender: opts.sender,
|
|
98
|
+
recipient: opts.recipient,
|
|
99
|
+
ttlMs: opts.ttlMs ?? 30_000,
|
|
100
|
+
intent: 'TASK',
|
|
101
|
+
content,
|
|
102
|
+
})
|
|
103
|
+
// embed sequence number in correlationId to help downstream ordering
|
|
104
|
+
;(envelope.body as any).correlationId = String(++seq)
|
|
105
|
+
const signed = await signEnvelopeEd25519(envelope, opts.privateKey)
|
|
106
|
+
ws.send(JSON.stringify(signed))
|
|
107
|
+
},
|
|
108
|
+
onMessage(handler) { messageHandlers.push(handler) },
|
|
109
|
+
onVerifyFail(handler) { failHandlers.push(handler) },
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ─────────────────── Stream signing over WebSocket ────────────────────────────
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* createSignedWebSocketStream
|
|
117
|
+
*
|
|
118
|
+
* Attaches a SignedStreamWriter to a WebSocket:
|
|
119
|
+
* - Each incoming WebSocket message is signed as a stream chunk and sent back.
|
|
120
|
+
* - On connection close, the final signed frame is sent.
|
|
121
|
+
*
|
|
122
|
+
* Returns the underlying SignedStreamWriter so callers can also call writeChunk
|
|
123
|
+
* directly (e.g. when driving the stream from application code rather than
|
|
124
|
+
* forwarding received messages).
|
|
125
|
+
*/
|
|
126
|
+
export function createSignedWebSocketStream(
|
|
127
|
+
ws: WebSocketLike,
|
|
128
|
+
opts: StreamSignerOpts,
|
|
129
|
+
): SignedStreamWriter {
|
|
130
|
+
const writer = new SignedStreamWriter(opts)
|
|
131
|
+
|
|
132
|
+
const messageListener = async (e: { data: string | Buffer }) => {
|
|
133
|
+
const data = typeof e.data === 'string' ? e.data : e.data.toString('utf8')
|
|
134
|
+
const chunk = await writer.writeChunk(data)
|
|
135
|
+
ws.send(encodeStreamChunk(chunk))
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const closeListener = async () => {
|
|
139
|
+
ws.removeEventListener('message', messageListener as any)
|
|
140
|
+
ws.removeEventListener('close', closeListener as any)
|
|
141
|
+
const finalChunk = await writer.finalize()
|
|
142
|
+
ws.send(encodeStreamChunk(finalChunk))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
ws.addEventListener('message', messageListener as any)
|
|
146
|
+
ws.addEventListener('close', closeListener as any)
|
|
147
|
+
|
|
148
|
+
return writer
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* receiveSignedWebSocketStream
|
|
153
|
+
*
|
|
154
|
+
* Listens for StreamChunk JSON frames on a WebSocket, accumulates them, and
|
|
155
|
+
* when the final frame (f=true) arrives calls verifyStream over the complete
|
|
156
|
+
* set of collected chunks.
|
|
157
|
+
*
|
|
158
|
+
* Resolves with StreamVerifyResult when the final frame is received.
|
|
159
|
+
* Rejects if a frame cannot be decoded.
|
|
160
|
+
*/
|
|
161
|
+
export function receiveSignedWebSocketStream(
|
|
162
|
+
ws: WebSocketLike,
|
|
163
|
+
opts: StreamVerifierOpts,
|
|
164
|
+
): Promise<StreamVerifyResult> {
|
|
165
|
+
return new Promise<StreamVerifyResult>((resolve, reject) => {
|
|
166
|
+
const collected: StreamChunk[] = []
|
|
167
|
+
|
|
168
|
+
const messageListener = async (e: { data: string | Buffer }) => {
|
|
169
|
+
const raw = typeof e.data === 'string' ? e.data : e.data.toString('utf8')
|
|
170
|
+
let chunk: StreamChunk
|
|
171
|
+
try {
|
|
172
|
+
chunk = decodeStreamChunk(raw)
|
|
173
|
+
} catch (err) {
|
|
174
|
+
cleanup()
|
|
175
|
+
reject(err)
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
collected.push(chunk)
|
|
179
|
+
if (chunk.f) {
|
|
180
|
+
cleanup()
|
|
181
|
+
const result = await verifyStream(collected, opts)
|
|
182
|
+
resolve(result)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const closeListener = () => {
|
|
187
|
+
// Connection closed before receiving final frame
|
|
188
|
+
cleanup()
|
|
189
|
+
resolve({ ok: false, reason: 'connection closed before final frame' })
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function cleanup() {
|
|
193
|
+
ws.removeEventListener('message', messageListener as any)
|
|
194
|
+
ws.removeEventListener('close', closeListener as any)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
ws.addEventListener('message', messageListener as any)
|
|
198
|
+
ws.addEventListener('close', closeListener as any)
|
|
199
|
+
})
|
|
200
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2023", "DOM"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"verbatimModuleSyntax": false
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts", "scripts/**/*.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"emitDeclarationOnly": true,
|
|
8
|
+
"declarationMap": false,
|
|
9
|
+
"sourceMap": false,
|
|
10
|
+
"outDir": "./dist/protocol",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"stripInternal": true,
|
|
13
|
+
"strict": true,
|
|
14
|
+
"types": ["node"],
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"noUnusedLocals": true,
|
|
17
|
+
"noUnusedParameters": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
|
19
|
+
"noUncheckedSideEffectImports": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["src/**/*.ts"],
|
|
22
|
+
"exclude": ["src/**/*.test.ts", "src/**/*.bench.ts"]
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
build: {
|
|
5
|
+
lib: {
|
|
6
|
+
entry: 'src/index.ts',
|
|
7
|
+
formats: ['es'],
|
|
8
|
+
fileName: () => 'index.js',
|
|
9
|
+
},
|
|
10
|
+
outDir: 'dist/protocol',
|
|
11
|
+
emptyOutDir: false,
|
|
12
|
+
rollupOptions: {
|
|
13
|
+
external: [],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
})
|
package/vitest.config.ts
ADDED
package/agentAdapter.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { type AgentReceiveResult, type AgentSessionConfig } from './protocolAgent';
|
|
2
|
-
import { type IntentKind, type ProtocolEnvelope } from './protocol';
|
|
3
|
-
import { type WireEnvelope, type WireFormat } from './protocolTransport';
|
|
4
|
-
export interface AipAdapterConfig extends AgentSessionConfig {
|
|
5
|
-
wireFormat?: WireFormat;
|
|
6
|
-
}
|
|
7
|
-
export declare class AipAgentAdapter {
|
|
8
|
-
private readonly session;
|
|
9
|
-
private readonly wireFormat;
|
|
10
|
-
constructor(config: AipAdapterConfig);
|
|
11
|
-
toRaw(envelope: ProtocolEnvelope): WireEnvelope;
|
|
12
|
-
createRawIntent(input: {
|
|
13
|
-
recipient?: string;
|
|
14
|
-
intent: IntentKind;
|
|
15
|
-
content: string;
|
|
16
|
-
capability?: string;
|
|
17
|
-
correlationId?: string;
|
|
18
|
-
ttlMs?: number;
|
|
19
|
-
messageId?: string;
|
|
20
|
-
nonce?: string;
|
|
21
|
-
nowMs?: number;
|
|
22
|
-
}): Promise<WireEnvelope>;
|
|
23
|
-
receiveRaw(raw: WireEnvelope, nowMs?: number): Promise<AgentReceiveResult>;
|
|
24
|
-
handleRaw(raw: WireEnvelope, emitResponseRaw: (rawResponse: WireEnvelope, responseEnvelope: ProtocolEnvelope) => void | Promise<void>, nowMs?: number): Promise<AgentReceiveResult>;
|
|
25
|
-
}
|
|
26
|
-
export declare function createAipAgentAdapter(config: AipAdapterConfig): AipAgentAdapter;
|
package/conformanceVectors.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ProtocolEnvelope } from './protocol';
|
|
2
|
-
export interface ConformanceVector {
|
|
3
|
-
id: string;
|
|
4
|
-
secret: string;
|
|
5
|
-
keyId: string;
|
|
6
|
-
envelope: Omit<ProtocolEnvelope, 'signature'>;
|
|
7
|
-
canonical: string;
|
|
8
|
-
signature: string;
|
|
9
|
-
}
|
|
10
|
-
export interface Ed25519ConformanceVector {
|
|
11
|
-
id: string;
|
|
12
|
-
keyId: string;
|
|
13
|
-
publicKey: string;
|
|
14
|
-
privateKey: string;
|
|
15
|
-
envelope: Omit<ProtocolEnvelope, 'signature'>;
|
|
16
|
-
canonical: string;
|
|
17
|
-
signature: string;
|
|
18
|
-
}
|
|
19
|
-
export declare const AIP_V01_CONFORMANCE_VECTORS: ConformanceVector[];
|
|
20
|
-
export declare const AIP_V01_ED25519_CONFORMANCE_VECTORS: Ed25519ConformanceVector[];
|