@7h3/protocol 0.4.0 → 0.5.1

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.
Files changed (248) hide show
  1. package/README.md +6 -323
  2. package/agentAdapter.d.ts +26 -0
  3. package/auditLog.d.ts +54 -0
  4. package/capability.d.ts +67 -0
  5. package/cborCodec.d.ts +34 -0
  6. package/conformanceVectors.d.ts +20 -0
  7. package/encryption.d.ts +85 -0
  8. package/envelopeCbor.d.ts +33 -0
  9. package/frameworkAdapters.d.ts +72 -0
  10. package/gateway.d.ts +53 -0
  11. package/grpcBinding.d.ts +29 -0
  12. package/httpBinding.d.ts +50 -0
  13. package/index.d.ts +39 -0
  14. package/index.js +3662 -0
  15. package/keyInfra.d.ts +64 -0
  16. package/keyRegistry.d.ts +9 -0
  17. package/keyRotation.d.ts +20 -0
  18. package/mcpGateway.d.ts +37 -0
  19. package/mcpTransports.d.ts +62 -0
  20. package/mcpWrapper.d.ts +83 -0
  21. package/otel.d.ts +65 -0
  22. package/package.json +13 -79
  23. package/policyEnforcer.d.ts +50 -0
  24. package/policyTelemetryFeedback.d.ts +11 -0
  25. package/protocol.d.ts +66 -0
  26. package/protocolAgent.d.ts +58 -0
  27. package/protocolBinary.d.ts +8 -0
  28. package/protocolCapabilities.d.ts +24 -0
  29. package/protocolReplay.d.ts +35 -0
  30. package/protocolTransport.d.ts +73 -0
  31. package/queueBinding.d.ts +43 -0
  32. package/rateLimiter.d.ts +18 -0
  33. package/{src/redisClient.ts → redisClient.d.ts} +25 -75
  34. package/replayStores.d.ts +98 -0
  35. package/revocation.d.ts +71 -0
  36. package/routePolicy.d.ts +30 -0
  37. package/runtimePolicy.d.ts +24 -0
  38. package/runtimePolicyManager.d.ts +15 -0
  39. package/runtimePolicyPresets.d.ts +11 -0
  40. package/signedResponse.d.ts +21 -0
  41. package/stream.d.ts +59 -0
  42. package/telemetry.d.ts +79 -0
  43. package/webhookBinding.d.ts +30 -0
  44. package/wsBinding.d.ts +52 -0
  45. package/.dockerignore +0 -19
  46. package/.github/dependabot.yml +0 -32
  47. package/.github/workflows/ci.yml +0 -31
  48. package/.github/workflows/publish.yml +0 -59
  49. package/.github/workflows/scorecard.yml +0 -37
  50. package/7h3.example.yaml +0 -125
  51. package/CHANGELOG.md +0 -92
  52. package/CONTRIBUTING.md +0 -82
  53. package/Dockerfile +0 -73
  54. package/GOVERNANCE.md +0 -62
  55. package/SECURITY.md +0 -70
  56. package/bench-results/replay-cache-full-1777891033256.json +0 -10
  57. package/bench-results/replay-cache-full-1777896317488.json +0 -10
  58. package/bench-results/replay-cache-full-1777900993184.json +0 -10
  59. package/bench-results/replay-cache-full-1777901019285.json +0 -10
  60. package/bench-results/replay-cache-quick-1777870170126.json +0 -10
  61. package/bench-results/signature-profiles-quick-1775875160079.json +0 -85
  62. package/bench-results/signature-profiles-quick-1775983539716.json +0 -85
  63. package/bench-results/signature-profiles-quick-1776237913190.json +0 -85
  64. package/bench-results/wire-codecs-full-1777891019803.json +0 -93
  65. package/bench-results/wire-codecs-full-1777896260964.json +0 -93
  66. package/bench-results/wire-codecs-full-1777901004247.json +0 -93
  67. package/bench-results/wire-codecs-quick-1775972879056.json +0 -93
  68. package/bench-results/wire-codecs-quick-1775983541111.json +0 -93
  69. package/bench-results/wire-codecs-quick-1776237914299.json +0 -93
  70. package/bench-results/wire-codecs-quick-1777841285236.json +0 -93
  71. package/bench-results/wire-codecs-quick-1777841321772.json +0 -93
  72. package/bench-results/wire-codecs-quick-1777841330408.json +0 -93
  73. package/bench-results/wire-codecs-quick-1777852886082.json +0 -93
  74. package/bench-results/wire-codecs-quick-1777852988773.json +0 -93
  75. package/bench-results/wire-codecs-quick-1777870188095.json +0 -93
  76. package/bench-results/wire-codecs-quick-1777870263918.json +0 -93
  77. package/bench-results/wire-codecs-quick-1777870455034.json +0 -93
  78. package/bench-results/wire-codecs-quick-1778816163081.json +0 -93
  79. package/bench-results/wire-codecs-quick-1778843936130.json +0 -93
  80. package/bin/7h3.ts +0 -385
  81. package/conformance/7h3_v0_1.json +0 -77
  82. package/conformance/7h3_v0_1_binary.json +0 -20
  83. package/conformance/aip_v0_1_binary.json +0 -20
  84. package/docker-compose.yaml +0 -77
  85. package/docs/ADOPTION_PLAN.md +0 -120
  86. package/docs/AGENTS.md +0 -77
  87. package/docs/AIP_RFC_v0.1.md +0 -97
  88. package/docs/AI_DECISION_CARD.md +0 -122
  89. package/docs/AI_RUNTIME_POLICY.json +0 -126
  90. package/docs/AI_RUNTIME_POLICY.yaml +0 -110
  91. package/docs/BACKPRESSURE_TUNING.md +0 -65
  92. package/docs/BENCHMARK_CLAIM_MATRIX.md +0 -42
  93. package/docs/BENCHMARK_REPORT_TEMPLATE.md +0 -169
  94. package/docs/BINARY_CODEC_BENCH.md +0 -23
  95. package/docs/CLEAN_CLONE_RUNBOOK.md +0 -36
  96. package/docs/CLOCK_SKEW_POLICY.md +0 -30
  97. package/docs/DISTRIBUTED_REPLAY.md +0 -142
  98. package/docs/FUZZ_CAMPAIGN.md +0 -121
  99. package/docs/GATEWAY.md +0 -195
  100. package/docs/KEY_MANAGEMENT_POLICY.md +0 -53
  101. package/docs/KEY_REVOCATION.md +0 -69
  102. package/docs/MCP_WRAPPER.md +0 -159
  103. package/docs/MIGRATION_GUIDE.md +0 -40
  104. package/docs/OPERATORS.md +0 -184
  105. package/docs/PERF_REGRESSION_POLICY.md +0 -34
  106. package/docs/PROJECT_EXAMINATION_2026-05-31.md +0 -219
  107. package/docs/RELEASE_BENCHMARK_REPORT_2026-05-15.md +0 -135
  108. package/docs/RELEASE_GATE.md +0 -25
  109. package/docs/RELEASE_NOTES_v0.1.0.md +0 -54
  110. package/docs/SECURITY_REVIEW_2026-06-05.md +0 -165
  111. package/docs/TELEMETRY.md +0 -41
  112. package/docs/THREAT_MODEL.md +0 -89
  113. package/docs/VERSIONING_POLICY.md +0 -30
  114. package/docs/assets/banner.png +0 -0
  115. package/eslint.config.js +0 -15
  116. package/fuzz/ts/harness-decode.ts +0 -136
  117. package/fuzz/ts/harness-verify.ts +0 -121
  118. package/fuzz/ts/run.ts +0 -35
  119. package/mcp-server/README.md +0 -38
  120. package/mcp-server/package-lock.json +0 -1187
  121. package/mcp-server/package.json +0 -35
  122. package/mcp-server/src/index.ts +0 -236
  123. package/mcp-server/tsconfig.json +0 -14
  124. package/scripts/aip-framework-quickstart.ts +0 -110
  125. package/scripts/aip-mcp-gateway.ts +0 -38
  126. package/scripts/aip-mcp-wrap-demo.ts +0 -72
  127. package/scripts/aip-quickstart.ts +0 -60
  128. package/scripts/bench-diff.ts +0 -118
  129. package/scripts/bench-protocol-e2e.ts +0 -937
  130. package/scripts/bench-protocol-openloop.ts +0 -1397
  131. package/scripts/bench-replay-cache.ts +0 -76
  132. package/scripts/bench-signature-profiles.ts +0 -180
  133. package/scripts/bench-wire-codecs.ts +0 -161
  134. package/scripts/build-binary-conformance.ts +0 -36
  135. package/scripts/build-release-dashboard.ts +0 -175
  136. package/scripts/canary-rollout.ts +0 -38
  137. package/scripts/mcpGatewayCli.test.ts +0 -116
  138. package/scripts/prepare-aip-package.ts +0 -88
  139. package/scripts/regen-conformance-sigs.ts +0 -18
  140. package/scripts/release-gate.ts +0 -19
  141. package/scripts/validate-runtime-policy.ts +0 -18
  142. package/sdk/browser/index.test.ts +0 -162
  143. package/sdk/browser/index.ts +0 -257
  144. package/sdk/browser/package.json +0 -13
  145. package/sdk/go/go.mod +0 -3
  146. package/sdk/go/http.go +0 -135
  147. package/sdk/go/protocol.go +0 -324
  148. package/sdk/go/protocol_test.go +0 -334
  149. package/sdk/go/webhook.go +0 -136
  150. package/sdk/python/README.md +0 -18
  151. package/sdk/python/protocol_7h3/__init__.py +0 -46
  152. package/sdk/python/protocol_7h3/http.py +0 -212
  153. package/sdk/python/protocol_7h3/keys.py +0 -149
  154. package/sdk/python/protocol_7h3/protocol.py +0 -525
  155. package/sdk/python/protocol_7h3/queue.py +0 -118
  156. package/sdk/python/protocol_7h3/webhook.py +0 -116
  157. package/sdk/python/pyproject.toml +0 -40
  158. package/sdk/python/tests/test_conformance.py +0 -110
  159. package/sdk/python/tests/test_http.py +0 -305
  160. package/sdk/python/tests/test_keys.py +0 -417
  161. package/sdk/python/tests/test_queue.py +0 -120
  162. package/sdk/python/tests/test_webhook.py +0 -345
  163. package/sdk/rust/Cargo.lock +0 -371
  164. package/sdk/rust/Cargo.toml +0 -25
  165. package/sdk/rust/README.md +0 -31
  166. package/sdk/rust/fuzz/Cargo.toml +0 -29
  167. package/sdk/rust/fuzz/fuzz_targets/fuzz_canonicalize.rs +0 -46
  168. package/sdk/rust/fuzz/fuzz_targets/fuzz_decode.rs +0 -11
  169. package/sdk/rust/src/bin/aip_mcp_gateway.rs +0 -59
  170. package/sdk/rust/src/http.rs +0 -145
  171. package/sdk/rust/src/keys.rs +0 -161
  172. package/sdk/rust/src/lib.rs +0 -688
  173. package/sdk/rust/src/queue.rs +0 -79
  174. package/sdk/rust/src/webhook.rs +0 -86
  175. package/sdk/rust/tests/conformance.rs +0 -148
  176. package/sdk/rust/tests/gateway.rs +0 -130
  177. package/sdk/rust/tests/http_webhook_queue.rs +0 -201
  178. package/sdk/rust/tests/keys.rs +0 -189
  179. package/src/agentAdapter.test.ts +0 -48
  180. package/src/agentAdapter.ts +0 -56
  181. package/src/auditLog.test.ts +0 -145
  182. package/src/auditLog.ts +0 -147
  183. package/src/conformance.test.ts +0 -136
  184. package/src/conformanceVectors.ts +0 -99
  185. package/src/frameworkAdapters.test.ts +0 -290
  186. package/src/frameworkAdapters.ts +0 -261
  187. package/src/gateway.test.ts +0 -343
  188. package/src/gateway.ts +0 -171
  189. package/src/grpcBinding.test.ts +0 -211
  190. package/src/grpcBinding.ts +0 -103
  191. package/src/httpBinding.test.ts +0 -376
  192. package/src/httpBinding.ts +0 -163
  193. package/src/index.ts +0 -32
  194. package/src/keyInfra.test.ts +0 -278
  195. package/src/keyInfra.ts +0 -228
  196. package/src/keyRegistry.ts +0 -59
  197. package/src/keyRotation.test.ts +0 -78
  198. package/src/keyRotation.ts +0 -72
  199. package/src/mcpGateway.test.ts +0 -129
  200. package/src/mcpGateway.ts +0 -250
  201. package/src/mcpTransports.test.ts +0 -92
  202. package/src/mcpTransports.ts +0 -169
  203. package/src/mcpWrapper.test.ts +0 -179
  204. package/src/mcpWrapper.ts +0 -206
  205. package/src/policyEnforcer.test.ts +0 -99
  206. package/src/policyEnforcer.ts +0 -169
  207. package/src/policyTelemetryFeedback.test.ts +0 -25
  208. package/src/policyTelemetryFeedback.ts +0 -38
  209. package/src/protocol.bench.ts +0 -37
  210. package/src/protocol.test.ts +0 -155
  211. package/src/protocol.ts +0 -413
  212. package/src/protocolAgent.test.ts +0 -105
  213. package/src/protocolAgent.ts +0 -169
  214. package/src/protocolBinary.test.ts +0 -165
  215. package/src/protocolBinary.ts +0 -312
  216. package/src/protocolCapabilities.ts +0 -70
  217. package/src/protocolFuzz.advanced.test.ts +0 -235
  218. package/src/protocolFuzz.test.ts +0 -111
  219. package/src/protocolNegative.test.ts +0 -97
  220. package/src/protocolReplay.test.ts +0 -71
  221. package/src/protocolReplay.ts +0 -194
  222. package/src/protocolTransport.test.ts +0 -556
  223. package/src/protocolTransport.ts +0 -483
  224. package/src/queueBinding.test.ts +0 -130
  225. package/src/queueBinding.ts +0 -102
  226. package/src/rateLimiter.test.ts +0 -96
  227. package/src/rateLimiter.ts +0 -46
  228. package/src/redisIntegration.test.ts +0 -134
  229. package/src/replayStores.test.ts +0 -141
  230. package/src/replayStores.ts +0 -82
  231. package/src/revocation.test.ts +0 -98
  232. package/src/revocation.ts +0 -0
  233. package/src/routePolicy.test.ts +0 -87
  234. package/src/routePolicy.ts +0 -72
  235. package/src/runtimePolicy.test.ts +0 -49
  236. package/src/runtimePolicy.ts +0 -81
  237. package/src/runtimePolicyManager.test.ts +0 -29
  238. package/src/runtimePolicyManager.ts +0 -50
  239. package/src/runtimePolicyPresets.ts +0 -43
  240. package/src/signedResponse.test.ts +0 -111
  241. package/src/signedResponse.ts +0 -83
  242. package/src/webhookBinding.test.ts +0 -144
  243. package/src/webhookBinding.ts +0 -115
  244. package/src/wsBinding.test.ts +0 -221
  245. package/src/wsBinding.ts +0 -100
  246. package/tsconfig.json +0 -15
  247. package/tsconfig.lib.json +0 -23
  248. package/vite.lib.config.ts +0 -16
@@ -0,0 +1,24 @@
1
+ import type { WireFormat } from './protocolTransport';
2
+ export type AckMode = 'fast' | 'receipt';
3
+ export interface AipCapabilities {
4
+ agent: string;
5
+ capabilities: string[];
6
+ wireFormats: WireFormat[];
7
+ batchMax: number;
8
+ ackModes: AckMode[];
9
+ }
10
+ export interface NegotiatedAipCapabilities {
11
+ wireFormat: WireFormat;
12
+ batchMax: number;
13
+ ackMode: AckMode;
14
+ }
15
+ export declare function createAipCapabilities(input: {
16
+ agent: string;
17
+ capabilities?: string[];
18
+ wireFormats?: WireFormat[];
19
+ batchMax?: number;
20
+ ackModes?: AckMode[];
21
+ }): AipCapabilities;
22
+ export declare function encodeAipCapabilities(capabilities: AipCapabilities): string;
23
+ export declare function parseAipCapabilities(raw: string): AipCapabilities | null;
24
+ export declare function negotiateAipCapabilities(local: AipCapabilities, remote: AipCapabilities): NegotiatedAipCapabilities;
@@ -0,0 +1,35 @@
1
+ import type { ProtocolEnvelope } from './protocol';
2
+ export interface ReplayCheckResult {
3
+ ok: boolean;
4
+ reason?: string;
5
+ }
6
+ export interface ReplayCache {
7
+ consume(envelope: ProtocolEnvelope, nowMs?: number): ReplayCheckResult | Promise<ReplayCheckResult>;
8
+ consumeMany?(envelopes: ProtocolEnvelope[], nowMs?: number): ReplayCheckResult[] | Promise<ReplayCheckResult[]>;
9
+ }
10
+ export interface DistributedReplayStore {
11
+ reserve(key: string, expiresAtMs: number, nowMs: number): boolean | Promise<boolean>;
12
+ /** Optional batch reserve; enables single round-trip checks for batched envelopes. */
13
+ reserveMany?(entries: Array<{
14
+ key: string;
15
+ expiresAtMs: number;
16
+ }>, nowMs: number): boolean[] | Promise<boolean[]>;
17
+ }
18
+ export declare class InMemoryReplayCache implements ReplayCache {
19
+ private readonly entries;
20
+ private readonly maxEntries;
21
+ private readonly expiries;
22
+ constructor(maxEntries?: number);
23
+ private makeKey;
24
+ prune(nowMs?: number): void;
25
+ private evictOne;
26
+ consume(envelope: ProtocolEnvelope, nowMs?: number): ReplayCheckResult;
27
+ consumeMany(envelopes: ProtocolEnvelope[], nowMs?: number): ReplayCheckResult[];
28
+ }
29
+ export declare class DistributedReplayCache implements ReplayCache {
30
+ private readonly store;
31
+ constructor(store: DistributedReplayStore);
32
+ private makeKey;
33
+ consume(envelope: ProtocolEnvelope, nowMs?: number): Promise<ReplayCheckResult>;
34
+ consumeMany(envelopes: ProtocolEnvelope[], nowMs?: number): Promise<ReplayCheckResult[]>;
35
+ }
@@ -0,0 +1,73 @@
1
+ import { type SignatureVerificationMaterial, type IntentKind, type ProtocolDiagnostic, type ProtocolEnvelope } from './protocol';
2
+ import { type ReplayCache } from './protocolReplay';
3
+ export type WireFormat = 'json' | 'compact' | 'binary';
4
+ export type BatchWireFormat = Exclude<WireFormat, 'binary'>;
5
+ export interface ReceiveEnvelopeOptions {
6
+ nowMs?: number;
7
+ requireSignature?: boolean;
8
+ maxClockSkewMs?: number;
9
+ replayCache?: ReplayCache;
10
+ verificationMaterialCache?: VerificationMaterialCache;
11
+ secretResolver?: (keyId: string, sender: string) => string | undefined | Promise<string | undefined>;
12
+ signatureResolver?: (signature: NonNullable<ProtocolEnvelope['signature']>, sender: string) => SignatureVerificationMaterial | undefined | Promise<SignatureVerificationMaterial | undefined>;
13
+ telemetry?: (event: TransportTelemetryEvent) => void | Promise<void>;
14
+ }
15
+ export interface ReceiveEnvelopeBatchOptions extends ReceiveEnvelopeOptions {
16
+ batchConcurrency?: number;
17
+ }
18
+ export interface TransportTelemetryEvent {
19
+ phase: 'decoded' | 'rejected_clock_skew' | 'rejected_validation' | 'rejected_replay' | 'rejected_missing_signature' | 'rejected_missing_material' | 'rejected_bad_signature' | 'batch_summary' | 'accepted';
20
+ nowMs: number;
21
+ sender?: string;
22
+ messageId?: string;
23
+ reason?: string;
24
+ }
25
+ export interface ReceiveEnvelopeResult {
26
+ ok: boolean;
27
+ diagnostics: ProtocolDiagnostic[];
28
+ envelope: ProtocolEnvelope | null;
29
+ }
30
+ export interface VerificationMaterialCache {
31
+ get(key: string, nowMs?: number): SignatureVerificationMaterial | undefined;
32
+ set(key: string, material: SignatureVerificationMaterial, expiresAtMs: number): void;
33
+ delete?(key: string): void;
34
+ }
35
+ export declare class InMemoryVerificationMaterialCache implements VerificationMaterialCache {
36
+ private readonly entries;
37
+ private readonly maxEntries;
38
+ constructor(maxEntries?: number);
39
+ get(key: string, nowMs?: number): SignatureVerificationMaterial | undefined;
40
+ set(key: string, material: SignatureVerificationMaterial, expiresAtMs: number): void;
41
+ delete(key: string): void;
42
+ }
43
+ export type WireEnvelope = string | Uint8Array;
44
+ export declare function decodeEnvelope(raw: WireEnvelope): ReceiveEnvelopeResult;
45
+ export declare function encodeEnvelope(envelope: ProtocolEnvelope, format: 'binary'): Uint8Array;
46
+ export declare function encodeEnvelope(envelope: ProtocolEnvelope, format?: 'json' | 'compact'): string;
47
+ export declare function encodeEnvelope(envelope: ProtocolEnvelope, format: WireFormat): WireEnvelope;
48
+ export declare function encodeEnvelopeBatch(envelopes: ProtocolEnvelope[], format?: BatchWireFormat): string;
49
+ export declare function decodeEnvelopeBatch(raw: string): ReceiveEnvelopeResult[];
50
+ export declare function receiveEnvelope(input: WireEnvelope | ProtocolEnvelope, options?: ReceiveEnvelopeOptions): Promise<ReceiveEnvelopeResult>;
51
+ export declare function receiveEnvelopeBatch(input: string | Array<WireEnvelope | ProtocolEnvelope>, options?: ReceiveEnvelopeBatchOptions): Promise<ReceiveEnvelopeResult[]>;
52
+ export declare class SessionTransport {
53
+ private readonly options;
54
+ constructor(options?: Omit<ReceiveEnvelopeOptions, 'replayCache'> & {
55
+ replayCache?: ReplayCache;
56
+ });
57
+ receive(input: WireEnvelope | ProtocolEnvelope, nowMs?: number): Promise<ReceiveEnvelopeResult>;
58
+ receiveBatch(input: string | Array<WireEnvelope | ProtocolEnvelope>, nowMs?: number): Promise<ReceiveEnvelopeResult[]>;
59
+ }
60
+ export declare function createSignedMessage(input: {
61
+ sender: string;
62
+ recipient?: string;
63
+ intent: IntentKind;
64
+ content: string;
65
+ capability?: string;
66
+ correlationId?: string;
67
+ ttlMs?: number;
68
+ messageId?: string;
69
+ nonce?: string;
70
+ nowMs?: number;
71
+ secret: string;
72
+ keyId?: string;
73
+ }): Promise<ProtocolEnvelope>;
@@ -0,0 +1,43 @@
1
+ import { type ProtocolEnvelope } from './protocol';
2
+ export interface QueueSignOptions {
3
+ privateKey: string;
4
+ sender: string;
5
+ recipient?: string;
6
+ ttlMs?: number;
7
+ keyId?: string;
8
+ }
9
+ export interface QueueVerifyOptions {
10
+ publicKey: string;
11
+ }
12
+ export type SignedEnvelope = ProtocolEnvelope;
13
+ export interface QueueMessage<T> {
14
+ envelope: SignedEnvelope;
15
+ payload: T;
16
+ }
17
+ /**
18
+ * Signs a payload for queue transit (Kafka/SQS/Pub-Sub/RabbitMQ).
19
+ * Returns a JSON string: {"envelope": SignedEnvelope, "payload": T}
20
+ * Default TTL is 1 hour (3 600 000 ms).
21
+ */
22
+ export declare function signQueueMessage<T>(payload: T, opts: QueueSignOptions): Promise<string>;
23
+ /**
24
+ * Parses a queue message JSON string and verifies the envelope signature.
25
+ * Throws if the message is malformed or the signature is invalid.
26
+ */
27
+ export declare function verifyQueueMessage<T>(message: string, opts: QueueVerifyOptions): Promise<{
28
+ payload: T;
29
+ envelope: ProtocolEnvelope;
30
+ }>;
31
+ /**
32
+ * Verifies a batch of queue message strings.
33
+ * Never throws — returns per-message success/failure objects.
34
+ */
35
+ export declare function verifyQueueBatch<T>(messages: string[], opts: QueueVerifyOptions): Promise<Array<{
36
+ ok: true;
37
+ payload: T;
38
+ envelope: ProtocolEnvelope;
39
+ } | {
40
+ ok: false;
41
+ raw: string;
42
+ error: string;
43
+ }>>;
@@ -0,0 +1,18 @@
1
+ export type RateLimitPolicy = {
2
+ requests: number;
3
+ windowMs: number;
4
+ };
5
+ export type RateLimitResult = {
6
+ allowed: boolean;
7
+ remaining: number;
8
+ resetMs: number;
9
+ };
10
+ declare class SlidingWindowRateLimiter {
11
+ private windows;
12
+ check(key: string, policy: RateLimitPolicy, nowMs?: number): RateLimitResult;
13
+ consume(key: string, policy: RateLimitPolicy, nowMs?: number): RateLimitResult;
14
+ reset(key: string): void;
15
+ clear(): void;
16
+ }
17
+ export declare const globalRateLimiter: SlidingWindowRateLimiter;
18
+ export { SlidingWindowRateLimiter };
@@ -46,36 +46,27 @@
46
46
  * denial-of-service vector. Choose the posture that matches your threat model.
47
47
  * - See `docs/DISTRIBUTED_REPLAY.md` for full operational guidance.
48
48
  */
49
-
50
49
  export interface RedisSetOptions {
51
- /** Only set when the key does not already exist (Redis `NX`). */
52
- nx?: boolean
53
- /** Expire the key after this many milliseconds (Redis `PX`). */
54
- pxMs?: number
50
+ /** Only set when the key does not already exist (Redis `NX`). */
51
+ nx?: boolean;
52
+ /** Expire the key after this many milliseconds (Redis `PX`). */
53
+ pxMs?: number;
55
54
  }
56
-
57
55
  /** A queued, chainable batch of `set` commands flushed in a single round-trip. */
58
56
  export interface RedisPipelineLike {
59
- set(key: string, value: string, options?: RedisSetOptions): RedisPipelineLike
60
- exec(): Promise<Array<'OK' | null>>
57
+ set(key: string, value: string, options?: RedisSetOptions): RedisPipelineLike;
58
+ exec(): Promise<Array<'OK' | null>>;
61
59
  }
62
-
63
60
  export interface RedisLikeClient {
64
- /** Returns `'OK'` when the value was written, or `null` when `NX` prevented it. */
65
- set(key: string, value: string, options?: RedisSetOptions): Promise<'OK' | null>
66
- /** Truthy when the key exists and has not expired. */
67
- get?(key: string): Promise<string | null>
68
- /** Removes a key; returns the number of keys removed. */
69
- del?(key: string): Promise<number>
70
- /** Optional batch pipeline; when present, batch reserves use a single round-trip. */
71
- pipeline?(): RedisPipelineLike
61
+ /** Returns `'OK'` when the value was written, or `null` when `NX` prevented it. */
62
+ set(key: string, value: string, options?: RedisSetOptions): Promise<'OK' | null>;
63
+ /** Truthy when the key exists and has not expired. */
64
+ get?(key: string): Promise<string | null>;
65
+ /** Removes a key; returns the number of keys removed. */
66
+ del?(key: string): Promise<number>;
67
+ /** Optional batch pipeline; when present, batch reserves use a single round-trip. */
68
+ pipeline?(): RedisPipelineLike;
72
69
  }
73
-
74
- interface Entry {
75
- value: string
76
- expiresAt?: number
77
- }
78
-
79
70
  /**
80
71
  * In-memory reference implementation of {@link RedisLikeClient}.
81
72
  *
@@ -85,56 +76,15 @@ interface Entry {
85
76
  * cross-process guarantees and must not be used as a production replay store
86
77
  * for a horizontally scaled deployment.
87
78
  */
88
- export class InMemoryRedisLikeClient implements RedisLikeClient {
89
- private readonly entries = new Map<string, Entry>()
90
- private readonly now: () => number
91
-
92
- constructor(options: { now?: () => number } = {}) {
93
- this.now = options.now ?? (() => Date.now())
94
- }
95
-
96
- private live(key: string): Entry | undefined {
97
- const entry = this.entries.get(key)
98
- if (!entry) return undefined
99
- if (entry.expiresAt !== undefined && entry.expiresAt <= this.now()) {
100
- this.entries.delete(key)
101
- return undefined
102
- }
103
- return entry
104
- }
105
-
106
- async set(key: string, value: string, options: RedisSetOptions = {}): Promise<'OK' | null> {
107
- if (options.nx && this.live(key)) return null
108
- const expiresAt = options.pxMs !== undefined ? this.now() + options.pxMs : undefined
109
- this.entries.set(key, { value, expiresAt })
110
- return 'OK'
111
- }
112
-
113
- async get(key: string): Promise<string | null> {
114
- return this.live(key)?.value ?? null
115
- }
116
-
117
- async del(key: string): Promise<number> {
118
- const existed = this.live(key) !== undefined
119
- this.entries.delete(key)
120
- return existed ? 1 : 0
121
- }
122
-
123
- pipeline(): RedisPipelineLike {
124
- const commands: Array<{ key: string; value: string; options?: RedisSetOptions }> = []
125
- const pipeline: RedisPipelineLike = {
126
- set: (key: string, value: string, options?: RedisSetOptions) => {
127
- commands.push({ key, value, options })
128
- return pipeline
129
- },
130
- exec: async () => {
131
- const results: Array<'OK' | null> = []
132
- for (const command of commands) {
133
- results.push(await this.set(command.key, command.value, command.options))
134
- }
135
- return results
136
- },
137
- }
138
- return pipeline
139
- }
79
+ export declare class InMemoryRedisLikeClient implements RedisLikeClient {
80
+ private readonly entries;
81
+ private readonly now;
82
+ constructor(options?: {
83
+ now?: () => number;
84
+ });
85
+ private live;
86
+ set(key: string, value: string, options?: RedisSetOptions): Promise<'OK' | null>;
87
+ get(key: string): Promise<string | null>;
88
+ del(key: string): Promise<number>;
89
+ pipeline(): RedisPipelineLike;
140
90
  }
@@ -0,0 +1,98 @@
1
+ import type { DistributedReplayStore } from './protocolReplay';
2
+ import { type RedisLikeClient } from './redisClient';
3
+ /**
4
+ * Minimal Redis client surface required by RedisReplayStore.
5
+ *
6
+ * Distinct from the internal RedisLikeClient: this interface uses a `quit()`
7
+ * lifecycle method and does not require pipeline support, making it easy to
8
+ * adapt any Redis client (ioredis, node-redis, Upstash, etc.) without coupling
9
+ * to the internal pipeline abstraction.
10
+ */
11
+ export interface RedisClientLike {
12
+ set(key: string, value: string, opts?: {
13
+ nx?: boolean;
14
+ px?: number;
15
+ }): Promise<string | null>;
16
+ get(key: string): Promise<string | null>;
17
+ del(key: string): Promise<number | any>;
18
+ quit(): Promise<any>;
19
+ }
20
+ /**
21
+ * Gateway-facing replay store interface.
22
+ *
23
+ * `check()` atomically marks a key as seen and returns whether it was already
24
+ * present: `false` = fresh (first time seen), `true` = replay (already seen).
25
+ */
26
+ export interface ReplayStore {
27
+ check(key: string, ttlMs: number): Promise<boolean>;
28
+ }
29
+ /**
30
+ * Redis-backed implementation of {@link ReplayStore}.
31
+ *
32
+ * Uses SET … NX PX for an atomic "set if not exists with TTL" operation.
33
+ * The operation is single-round-trip and safe under concurrent access from
34
+ * multiple gateway instances.
35
+ */
36
+ export declare class RedisReplayStore implements ReplayStore {
37
+ private readonly keyPrefix;
38
+ private readonly client;
39
+ constructor(opts?: {
40
+ redisUrl?: string;
41
+ keyPrefix?: string;
42
+ client?: RedisClientLike;
43
+ });
44
+ /**
45
+ * Returns `false` if the key is fresh (first time seen — key was set in Redis),
46
+ * or `true` if the key is a replay (key already existed — SET NX returned null).
47
+ */
48
+ check(key: string, ttlMs: number): Promise<boolean>;
49
+ }
50
+ /**
51
+ * Cluster-aware replay store that wraps multiple {@link RedisReplayStore}
52
+ * instances — one per Redis shard / node.
53
+ *
54
+ * A message is treated as a replay if ANY node has already seen the nonce.
55
+ * All nodes are checked in parallel via Promise.all.
56
+ */
57
+ export declare class ClusterRedisReplayStore implements ReplayStore {
58
+ private readonly nodes;
59
+ constructor(nodes: RedisReplayStore[]);
60
+ check(key: string, ttlMs: number): Promise<boolean>;
61
+ }
62
+ /**
63
+ * Convenience factory that creates a {@link RedisReplayStore} from a URL
64
+ * or options object.
65
+ */
66
+ export declare function createRedisReplayStore(clientOrOpts: RedisLikeClient | {
67
+ redisUrl?: string;
68
+ keyPrefix?: string;
69
+ client?: RedisClientLike;
70
+ }, options?: RedisReplayStoreOptions): DistributedReplayStore;
71
+ /**
72
+ * Creates a {@link ClusterRedisReplayStore} from an array of Redis URLs.
73
+ * Each URL is used to create an independent {@link RedisReplayStore} node.
74
+ */
75
+ export declare function createClusterReplayStore(redisUrls: string[]): ClusterRedisReplayStore;
76
+ /**
77
+ * What to do when the Redis client throws (network blip, server down).
78
+ *
79
+ * - `fallback` (default): degrade to a local in-memory store so traffic keeps
80
+ * flowing with single-node replay protection still in force. Quality +
81
+ * reliability + scalability: Redis is never a fleet-wide kill switch.
82
+ * - `reject`: fail closed — deny the message because uniqueness cannot be confirmed.
83
+ * - `allow`: fail open — accept the message (skip the check) to maximise uptime.
84
+ */
85
+ export type ReplayErrorBehavior = 'fallback' | 'reject' | 'allow';
86
+ export interface RedisReplayStoreOptions {
87
+ /** Key namespace in Redis. Default `aip:replay:`. */
88
+ keyPrefix?: string;
89
+ /** Behavior when the Redis client throws. Default `fallback`. */
90
+ errorBehavior?: ReplayErrorBehavior;
91
+ /** Local store used when `errorBehavior` is `fallback`. Defaults to an in-memory-backed store. */
92
+ fallback?: DistributedReplayStore;
93
+ /** Observability hook fired whenever a Redis error forces degraded handling. */
94
+ onDegraded?: (error: unknown, context: {
95
+ key: string;
96
+ behavior: ReplayErrorBehavior;
97
+ }) => void;
98
+ }
@@ -0,0 +1,71 @@
1
+ import type { ProtocolEnvelope, SignatureVerificationMaterial } from './protocol';
2
+ import type { RedisLikeClient } from './redisClient';
3
+ /**
4
+ * A shared key-revocation list consulted on the verification hot path.
5
+ *
6
+ * `RollingKeyring` enforces revocation in-process; a `RevocationStore` makes a
7
+ * revocation effective fleet-wide: revoke a `(sender, keyId)` on one node and
8
+ * every node that consults the same store rejects it.
9
+ */
10
+ export interface RevocationStore {
11
+ isRevoked(sender: string, keyId: string, nowMs?: number): boolean | Promise<boolean>;
12
+ revoke(sender: string, keyId: string, options?: {
13
+ untilMs?: number;
14
+ }): void | Promise<void>;
15
+ }
16
+ /** Single-process revocation list (tests, local dev, single-node deployments). */
17
+ export declare class InMemoryRevocationStore implements RevocationStore {
18
+ /** keyId map value: revoked-until timestamp, or `Infinity` for permanent. */
19
+ private readonly revoked;
20
+ private readonly now;
21
+ constructor(options?: {
22
+ now?: () => number;
23
+ });
24
+ private makeKey;
25
+ isRevoked(sender: string, keyId: string, nowMs?: number): boolean;
26
+ revoke(sender: string, keyId: string, options?: {
27
+ untilMs?: number;
28
+ }): void;
29
+ }
30
+ /** Behavior when the Redis client throws while checking revocation. */
31
+ export type RevocationErrorBehavior = 'reject' | 'allow';
32
+ export interface RedisRevocationStoreOptions {
33
+ /** Key namespace in Redis. Default `aip:revoked:`. */
34
+ keyPrefix?: string;
35
+ /**
36
+ * Behavior when the Redis client throws.
37
+ * - `reject` (default): fail closed — treat the key as revoked. A revoked key
38
+ * is a compromised key; never accept on uncertainty.
39
+ * - `allow`: treat the key as not revoked (favor availability).
40
+ */
41
+ errorBehavior?: RevocationErrorBehavior;
42
+ /** Local cache freshness window in ms for `isRevoked` reads. Default 5000. */
43
+ cacheTtlMs?: number;
44
+ /** Observability hook fired whenever a Redis error forces degraded handling. */
45
+ onDegraded?: (error: unknown, context: {
46
+ sender: string;
47
+ keyId: string;
48
+ }) => void;
49
+ /** Clock override (testing). */
50
+ now?: () => number;
51
+ }
52
+ /**
53
+ * Creates a Redis-backed {@link RevocationStore}.
54
+ *
55
+ * Reads are served from a short-lived local cache so the verification hot path
56
+ * does not hit Redis on every message; known revocations therefore keep
57
+ * enforcing even through a brief Redis outage.
58
+ */
59
+ export declare function createRedisRevocationStore(client: Pick<RedisLikeClient, 'set' | 'get' | 'del'>, options?: RedisRevocationStoreOptions): RevocationStore;
60
+ type SignatureResolver = (signature: NonNullable<ProtocolEnvelope['signature']>, sender: string) => SignatureVerificationMaterial | undefined | Promise<SignatureVerificationMaterial | undefined>;
61
+ /**
62
+ * Wraps a signature resolver so that a revoked `(sender, keyId)` resolves to no
63
+ * material — which makes signature verification fail and the envelope is rejected.
64
+ *
65
+ * Compose over `createKeyringSignatureResolver` (or any resolver) and pass the
66
+ * result as the transport `signatureResolver`.
67
+ */
68
+ export declare function withRevocationCheck(resolver: SignatureResolver, store: RevocationStore, options?: {
69
+ nowMsProvider?: () => number;
70
+ }): SignatureResolver;
71
+ export {};
@@ -0,0 +1,30 @@
1
+ export type PolicyRequirement = 'ed25519' | 'hmac' | 'any' | 'none';
2
+ export interface RoutePolicy {
3
+ path: string;
4
+ require: PolicyRequirement;
5
+ rateLimit?: {
6
+ requests: number;
7
+ windowMs: number;
8
+ };
9
+ allowedSenders?: string[];
10
+ signResponse?: boolean;
11
+ }
12
+ /**
13
+ * Translate a glob pattern to a RegExp.
14
+ * Supported:
15
+ * - exact: '/health'
16
+ * - '?' → any single non-slash char
17
+ * - '*' → any chars within a single segment (no slash)
18
+ * - '**' → any chars at any depth (including slashes)
19
+ */
20
+ export declare function matchGlob(pattern: string, path: string): boolean;
21
+ /**
22
+ * Find the first matching policy for a given path.
23
+ * Returns null if no policy matches.
24
+ */
25
+ export declare function matchPolicy(policies: RoutePolicy[], path: string): RoutePolicy | null;
26
+ /**
27
+ * Check whether a sender is permitted by a policy.
28
+ * If allowedSenders is not set, all senders are allowed.
29
+ */
30
+ export declare function isAllowedSender(policy: RoutePolicy, sender: string): boolean;
@@ -0,0 +1,24 @@
1
+ export interface RuntimePolicy {
2
+ version: string;
3
+ name: string;
4
+ status: string;
5
+ owner?: string;
6
+ updated_at?: string;
7
+ hard_invariants?: Record<string, unknown>;
8
+ slo_defaults?: Record<string, unknown>;
9
+ mode_selection?: Record<string, unknown>;
10
+ guardrails?: Record<string, unknown>;
11
+ tuning?: Record<string, unknown>;
12
+ adaptive_flow?: Record<string, unknown>;
13
+ benchmark_policy?: Record<string, unknown>;
14
+ runtime_decision_tree?: unknown[];
15
+ operator_handoff_required_fields?: string[];
16
+ [key: string]: unknown;
17
+ }
18
+ export interface LoadRuntimePolicyOptions {
19
+ path?: string;
20
+ readTextFile?: (filePath: string) => Promise<string>;
21
+ }
22
+ export declare function validateRuntimePolicy(value: unknown): RuntimePolicy;
23
+ export declare function parseRuntimePolicyJson(jsonText: string): RuntimePolicy;
24
+ export declare function loadRuntimePolicy(options?: LoadRuntimePolicyOptions): Promise<RuntimePolicy>;
@@ -0,0 +1,15 @@
1
+ import { type BootstrapRuntimePolicyEnforcerOptions, type PolicyEnforcer } from './policyEnforcer';
2
+ import type { RuntimePolicy } from './runtimePolicy';
3
+ export interface RuntimePolicySnapshot {
4
+ policy: RuntimePolicy;
5
+ enforcer: PolicyEnforcer;
6
+ loadedAtMs: number;
7
+ }
8
+ export declare class RuntimePolicyManager {
9
+ private snapshot;
10
+ private readonly options;
11
+ constructor(options?: BootstrapRuntimePolicyEnforcerOptions);
12
+ loadInitial(): Promise<RuntimePolicySnapshot>;
13
+ current(): RuntimePolicySnapshot;
14
+ refresh(): Promise<RuntimePolicySnapshot>;
15
+ }
@@ -0,0 +1,11 @@
1
+ import type { RuntimeMode } from './policyEnforcer';
2
+ export type RuntimeEnvironment = 'dev' | 'staging' | 'prod';
3
+ export interface RuntimeTuningPreset {
4
+ environment: RuntimeEnvironment;
5
+ mode: RuntimeMode;
6
+ poolSize: number;
7
+ batchSize: number;
8
+ inflightCap: number;
9
+ retryMaxAttempts: number;
10
+ }
11
+ export declare function getRuntimeTuningPreset(environment: RuntimeEnvironment): RuntimeTuningPreset;
@@ -0,0 +1,21 @@
1
+ import { type ProtocolEnvelope } from './protocol';
2
+ export declare const RESPONSE_HEADER = "x-7h3-response";
3
+ export declare function signResponse(body: string, opts: {
4
+ privateKey: string;
5
+ sender: string;
6
+ recipient?: string;
7
+ correlationId?: string;
8
+ ttlMs?: number;
9
+ }): Promise<{
10
+ headers: {
11
+ 'x-7h3-response': string;
12
+ };
13
+ }>;
14
+ export declare function verifyResponse(body: string, headers: Record<string, string | string[] | undefined>, opts: {
15
+ publicKey: string;
16
+ maxAgeMs?: number;
17
+ }): Promise<{
18
+ ok: boolean;
19
+ envelope?: ProtocolEnvelope;
20
+ reason?: string;
21
+ }>;
package/stream.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ export interface StreamChunk {
2
+ i: number;
3
+ d: string;
4
+ h: string;
5
+ f: boolean;
6
+ sig?: string;
7
+ kid?: string;
8
+ }
9
+ export interface StreamSignerOpts {
10
+ privateKey: string;
11
+ sender: string;
12
+ nonce?: string;
13
+ keyId?: string;
14
+ }
15
+ export interface StreamVerifierOpts {
16
+ publicKey: string;
17
+ maxChunks?: number;
18
+ }
19
+ export type StreamVerifyResult = {
20
+ ok: true;
21
+ totalBytes: number;
22
+ chunkCount: number;
23
+ } | {
24
+ ok: false;
25
+ reason: string;
26
+ chunkIndex?: number;
27
+ };
28
+ export declare const STREAM_HEADER = "x-7h3-stream";
29
+ export declare class SignedStreamWriter {
30
+ private readonly opts;
31
+ private seq;
32
+ private readonly accum;
33
+ private hmacKeyPromise;
34
+ constructor(opts: StreamSignerOpts);
35
+ get nonce(): string;
36
+ private getHmacKey;
37
+ private computeChunkHmac;
38
+ writeChunk(data: string): Promise<StreamChunk>;
39
+ finalize(): Promise<StreamChunk>;
40
+ }
41
+ export declare class SignedStreamReader {
42
+ private readonly opts;
43
+ private expectedSeq;
44
+ private readonly accum;
45
+ private totalBytes;
46
+ private done;
47
+ constructor(opts: StreamVerifierOpts);
48
+ receiveChunk(chunk: StreamChunk): Promise<{
49
+ ok: boolean;
50
+ reason?: string;
51
+ }>;
52
+ finalize(finalChunk: StreamChunk): Promise<StreamVerifyResult>;
53
+ }
54
+ export declare function createSignedStream(opts: StreamSignerOpts): SignedStreamWriter;
55
+ export declare function createStreamVerifier(opts: StreamVerifierOpts): SignedStreamReader;
56
+ export declare function signStream(chunks: AsyncIterable<string> | string[], opts: StreamSignerOpts): Promise<StreamChunk[]>;
57
+ export declare function verifyStream(chunks: StreamChunk[], opts: StreamVerifierOpts): Promise<StreamVerifyResult>;
58
+ export declare function encodeStreamChunk(chunk: StreamChunk): string;
59
+ export declare function decodeStreamChunk(raw: string): StreamChunk;