@7h3/protocol 0.5.0 → 0.5.2

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 (294) hide show
  1. package/README.md +6 -1317
  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 +3670 -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 -121
  23. package/policyEnforcer.d.ts +50 -0
  24. package/policyTelemetryFeedback.d.ts +11 -0
  25. package/{src/protocol.d.ts → protocol.d.ts} +6 -2
  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 -152
  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 -406
  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-github.png +0 -0
  115. package/docs/assets/banner.png +0 -0
  116. package/docs/assets/banner.svg +0 -123
  117. package/eslint.config.js +0 -15
  118. package/fuzz/ts/harness-decode.ts +0 -136
  119. package/fuzz/ts/harness-verify.ts +0 -121
  120. package/fuzz/ts/run.ts +0 -35
  121. package/mcp-server/README.md +0 -38
  122. package/mcp-server/package-lock.json +0 -1187
  123. package/mcp-server/package.json +0 -35
  124. package/mcp-server/src/index.ts +0 -236
  125. package/mcp-server/tsconfig.json +0 -14
  126. package/scripts/aip-framework-quickstart.ts +0 -110
  127. package/scripts/aip-mcp-gateway.ts +0 -38
  128. package/scripts/aip-mcp-wrap-demo.ts +0 -72
  129. package/scripts/aip-quickstart.ts +0 -60
  130. package/scripts/bench-diff.ts +0 -118
  131. package/scripts/bench-protocol-e2e.ts +0 -937
  132. package/scripts/bench-protocol-openloop.ts +0 -1397
  133. package/scripts/bench-replay-cache.ts +0 -76
  134. package/scripts/bench-signature-profiles.ts +0 -180
  135. package/scripts/bench-wire-codecs.ts +0 -161
  136. package/scripts/build-binary-conformance.ts +0 -36
  137. package/scripts/build-release-dashboard.ts +0 -175
  138. package/scripts/canary-rollout.ts +0 -38
  139. package/scripts/mcpGatewayCli.test.ts +0 -116
  140. package/scripts/prepare-aip-package.ts +0 -88
  141. package/scripts/regen-conformance-sigs.ts +0 -18
  142. package/scripts/release-gate.ts +0 -19
  143. package/scripts/validate-runtime-policy.ts +0 -18
  144. package/sdk/browser/index.test.ts +0 -162
  145. package/sdk/browser/index.ts +0 -257
  146. package/sdk/browser/package.json +0 -13
  147. package/sdk/go/cbor.go +0 -551
  148. package/sdk/go/cbor_test.go +0 -232
  149. package/sdk/go/encryption.go +0 -280
  150. package/sdk/go/encryption_test.go +0 -318
  151. package/sdk/go/go.mod +0 -7
  152. package/sdk/go/go.sum +0 -4
  153. package/sdk/go/http.go +0 -135
  154. package/sdk/go/protocol.go +0 -324
  155. package/sdk/go/protocol_test.go +0 -334
  156. package/sdk/go/replay.go +0 -121
  157. package/sdk/go/replay_test.go +0 -149
  158. package/sdk/go/webhook.go +0 -136
  159. package/sdk/pq/package-lock.json +0 -1358
  160. package/sdk/pq/package.json +0 -42
  161. package/sdk/pq/src/index.test.ts +0 -143
  162. package/sdk/pq/src/index.ts +0 -166
  163. package/sdk/pq/tsconfig.json +0 -14
  164. package/sdk/pq/vitest.config.ts +0 -7
  165. package/sdk/python/README.md +0 -18
  166. package/sdk/python/protocol_7h3/__init__.py +0 -46
  167. package/sdk/python/protocol_7h3/encryption.py +0 -252
  168. package/sdk/python/protocol_7h3/http.py +0 -212
  169. package/sdk/python/protocol_7h3/keys.py +0 -149
  170. package/sdk/python/protocol_7h3/pq.py +0 -244
  171. package/sdk/python/protocol_7h3/protocol.py +0 -525
  172. package/sdk/python/protocol_7h3/queue.py +0 -118
  173. package/sdk/python/protocol_7h3/replay.py +0 -98
  174. package/sdk/python/protocol_7h3/webhook.py +0 -116
  175. package/sdk/python/pyproject.toml +0 -40
  176. package/sdk/python/tests/test_conformance.py +0 -110
  177. package/sdk/python/tests/test_encryption.py +0 -206
  178. package/sdk/python/tests/test_http.py +0 -305
  179. package/sdk/python/tests/test_keys.py +0 -417
  180. package/sdk/python/tests/test_queue.py +0 -120
  181. package/sdk/python/tests/test_webhook.py +0 -345
  182. package/sdk/rust/Cargo.lock +0 -371
  183. package/sdk/rust/Cargo.toml +0 -25
  184. package/sdk/rust/README.md +0 -31
  185. package/sdk/rust/fuzz/Cargo.toml +0 -29
  186. package/sdk/rust/fuzz/fuzz_targets/fuzz_canonicalize.rs +0 -46
  187. package/sdk/rust/fuzz/fuzz_targets/fuzz_decode.rs +0 -11
  188. package/sdk/rust/src/bin/aip_mcp_gateway.rs +0 -59
  189. package/sdk/rust/src/http.rs +0 -145
  190. package/sdk/rust/src/keys.rs +0 -161
  191. package/sdk/rust/src/lib.rs +0 -688
  192. package/sdk/rust/src/queue.rs +0 -79
  193. package/sdk/rust/src/webhook.rs +0 -86
  194. package/sdk/rust/tests/conformance.rs +0 -148
  195. package/sdk/rust/tests/gateway.rs +0 -130
  196. package/sdk/rust/tests/http_webhook_queue.rs +0 -201
  197. package/sdk/rust/tests/keys.rs +0 -189
  198. package/sdk/threshold/index.d.ts +0 -68
  199. package/sdk/threshold/index.d.ts.map +0 -1
  200. package/sdk/threshold/index.js +0 -254
  201. package/sdk/threshold/package-lock.json +0 -1361
  202. package/sdk/threshold/package.json +0 -39
  203. package/sdk/threshold/src/index.d.ts +0 -68
  204. package/sdk/threshold/src/index.d.ts.map +0 -1
  205. package/sdk/threshold/src/index.js +0 -254
  206. package/sdk/threshold/src/index.test.ts +0 -238
  207. package/sdk/threshold/src/index.ts +0 -355
  208. package/sdk/threshold/tsconfig.json +0 -19
  209. package/sdk/threshold/vitest.config.ts +0 -12
  210. package/src/agentAdapter.test.ts +0 -48
  211. package/src/agentAdapter.ts +0 -56
  212. package/src/auditLog.test.ts +0 -145
  213. package/src/auditLog.ts +0 -147
  214. package/src/capability.test.ts +0 -504
  215. package/src/capability.ts +0 -380
  216. package/src/cborCodec.test.ts +0 -263
  217. package/src/cborCodec.ts +0 -339
  218. package/src/conformance.test.ts +0 -136
  219. package/src/conformanceVectors.ts +0 -99
  220. package/src/encryption.test.ts +0 -206
  221. package/src/encryption.ts +0 -245
  222. package/src/envelopeCbor.ts +0 -140
  223. package/src/frameworkAdapters.test.ts +0 -290
  224. package/src/frameworkAdapters.ts +0 -261
  225. package/src/gateway.test.ts +0 -343
  226. package/src/gateway.ts +0 -246
  227. package/src/grpcBinding.test.ts +0 -211
  228. package/src/grpcBinding.ts +0 -103
  229. package/src/httpBinding.test.ts +0 -376
  230. package/src/httpBinding.ts +0 -189
  231. package/src/index.ts +0 -39
  232. package/src/keyInfra.test.ts +0 -278
  233. package/src/keyInfra.ts +0 -228
  234. package/src/keyRegistry.ts +0 -59
  235. package/src/keyRotation.test.ts +0 -78
  236. package/src/keyRotation.ts +0 -72
  237. package/src/mcpGateway.test.ts +0 -129
  238. package/src/mcpGateway.ts +0 -250
  239. package/src/mcpTransports.test.ts +0 -92
  240. package/src/mcpTransports.ts +0 -169
  241. package/src/mcpWrapper.test.ts +0 -179
  242. package/src/mcpWrapper.ts +0 -206
  243. package/src/otel.ts +0 -136
  244. package/src/policyEnforcer.test.ts +0 -99
  245. package/src/policyEnforcer.ts +0 -169
  246. package/src/policyTelemetryFeedback.test.ts +0 -25
  247. package/src/policyTelemetryFeedback.ts +0 -38
  248. package/src/protocol.bench.ts +0 -37
  249. package/src/protocol.d.ts.map +0 -1
  250. package/src/protocol.js +0 -294
  251. package/src/protocol.test.ts +0 -155
  252. package/src/protocol.ts +0 -414
  253. package/src/protocolAgent.test.ts +0 -105
  254. package/src/protocolAgent.ts +0 -169
  255. package/src/protocolBinary.test.ts +0 -165
  256. package/src/protocolBinary.ts +0 -312
  257. package/src/protocolCapabilities.ts +0 -70
  258. package/src/protocolFuzz.advanced.test.ts +0 -235
  259. package/src/protocolFuzz.test.ts +0 -111
  260. package/src/protocolNegative.test.ts +0 -97
  261. package/src/protocolReplay.test.ts +0 -71
  262. package/src/protocolReplay.ts +0 -194
  263. package/src/protocolTransport.test.ts +0 -556
  264. package/src/protocolTransport.ts +0 -483
  265. package/src/queueBinding.test.ts +0 -130
  266. package/src/queueBinding.ts +0 -102
  267. package/src/rateLimiter.test.ts +0 -96
  268. package/src/rateLimiter.ts +0 -46
  269. package/src/redisIntegration.test.ts +0 -134
  270. package/src/replayStores.test.ts +0 -273
  271. package/src/replayStores.ts +0 -215
  272. package/src/revocation.test.ts +0 -98
  273. package/src/revocation.ts +0 -0
  274. package/src/routePolicy.test.ts +0 -87
  275. package/src/routePolicy.ts +0 -72
  276. package/src/runtimePolicy.test.ts +0 -49
  277. package/src/runtimePolicy.ts +0 -81
  278. package/src/runtimePolicyManager.test.ts +0 -29
  279. package/src/runtimePolicyManager.ts +0 -50
  280. package/src/runtimePolicyPresets.ts +0 -43
  281. package/src/signedResponse.test.ts +0 -111
  282. package/src/signedResponse.ts +0 -83
  283. package/src/stream.test.ts +0 -254
  284. package/src/stream.ts +0 -417
  285. package/src/telemetry.test.ts +0 -251
  286. package/src/telemetry.ts +0 -299
  287. package/src/webhookBinding.test.ts +0 -144
  288. package/src/webhookBinding.ts +0 -115
  289. package/src/wsBinding.test.ts +0 -221
  290. package/src/wsBinding.ts +0 -200
  291. package/tsconfig.json +0 -15
  292. package/tsconfig.lib.json +0 -23
  293. package/vite.lib.config.ts +0 -16
  294. package/vitest.config.ts +0 -11
@@ -1,116 +0,0 @@
1
- import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- interface JsonRpcEnvelope {
5
- jsonrpc: '2.0'
6
- id: string | number | null
7
- result?: unknown
8
- error?: {
9
- code: number
10
- message: string
11
- }
12
- }
13
-
14
- function waitForLine(child: ChildProcessWithoutNullStreams, timeoutMs = 8_000): Promise<string> {
15
- return new Promise((resolve, reject) => {
16
- let buffer = ''
17
- const timer = setTimeout(() => {
18
- cleanup()
19
- reject(new Error('Timed out waiting for gateway output'))
20
- }, timeoutMs)
21
-
22
- const onData = (chunk: Buffer) => {
23
- buffer += chunk.toString('utf8')
24
- const newlineIndex = buffer.indexOf('\n')
25
- if (newlineIndex >= 0) {
26
- const line = buffer.slice(0, newlineIndex).trim()
27
- cleanup()
28
- resolve(line)
29
- }
30
- }
31
-
32
- const onError = (error: Error) => {
33
- cleanup()
34
- reject(error)
35
- }
36
-
37
- const onExit = () => {
38
- cleanup()
39
- reject(new Error('Gateway process exited before producing output'))
40
- }
41
-
42
- const cleanup = () => {
43
- clearTimeout(timer)
44
- child.stdout.off('data', onData)
45
- child.off('error', onError)
46
- child.off('exit', onExit)
47
- }
48
-
49
- child.stdout.on('data', onData)
50
- child.on('error', onError)
51
- child.on('exit', onExit)
52
- })
53
- }
54
-
55
- function startGateway(extraEnv: Record<string, string> = {}): ChildProcessWithoutNullStreams {
56
- const child = spawn('npm', ['run', '-s', 'aip:mcp:gateway'], {
57
- cwd: process.cwd(),
58
- env: {
59
- ...process.env,
60
- ...extraEnv,
61
- },
62
- stdio: ['pipe', 'pipe', 'pipe'],
63
- })
64
-
65
- child.stderr.on('data', () => {
66
- // suppress stderr accumulation in test output
67
- })
68
-
69
- return child
70
- }
71
-
72
- async function stopGateway(child: ChildProcessWithoutNullStreams): Promise<void> {
73
- if (child.killed) return
74
- child.kill('SIGTERM')
75
- await new Promise<void>((resolve) => {
76
- child.once('exit', () => resolve())
77
- setTimeout(() => resolve(), 2_000)
78
- })
79
- }
80
-
81
- describe('AIP MCP gateway CLI', () => {
82
- it('returns JSON-RPC result for allowed method', async () => {
83
- const child = startGateway()
84
- try {
85
- child.stdin.write(
86
- `${JSON.stringify({ jsonrpc: '2.0', id: 99, method: 'tools/call', params: { name: 'planner' } })}\n`,
87
- )
88
- const line = await waitForLine(child)
89
- const response = JSON.parse(line) as JsonRpcEnvelope
90
-
91
- expect(response.jsonrpc).toBe('2.0')
92
- expect(response.id).toBe(99)
93
- expect(response.error).toBeUndefined()
94
- expect(response.result).toBeTruthy()
95
- } finally {
96
- await stopGateway(child)
97
- }
98
- })
99
-
100
- it('returns method-not-found for disallowed method from env policy', async () => {
101
- const child = startGateway({ AIP_ALLOWED_METHODS: 'tools/call' })
102
- try {
103
- child.stdin.write(
104
- `${JSON.stringify({ jsonrpc: '2.0', id: 'abc', method: 'resources/read', params: { uri: 'file://x' } })}\n`,
105
- )
106
- const line = await waitForLine(child)
107
- const response = JSON.parse(line) as JsonRpcEnvelope
108
-
109
- expect(response.id).toBe('abc')
110
- expect(response.result).toBeUndefined()
111
- expect(response.error?.code).toBe(-32601)
112
- } finally {
113
- await stopGateway(child)
114
- }
115
- })
116
- })
@@ -1,88 +0,0 @@
1
- import { mkdir, readFile, writeFile, copyFile, readdir } from 'node:fs/promises'
2
- import process from 'node:process'
3
-
4
- interface RootPackageJson {
5
- version?: string
6
- }
7
-
8
- function parseVersionArg(argv: string[]): string | undefined {
9
- const idx = argv.indexOf('--version')
10
- if (idx < 0) return undefined
11
- return argv[idx + 1]
12
- }
13
-
14
- async function readRootVersion(): Promise<string> {
15
- const raw = await readFile('package.json', 'utf8')
16
- const parsed = JSON.parse(raw) as RootPackageJson
17
- return parsed.version ?? '0.0.0'
18
- }
19
-
20
- async function main(): Promise<void> {
21
- const version = parseVersionArg(process.argv) ?? (await readRootVersion())
22
- const outDir = 'dist/npm-protocol'
23
-
24
- await mkdir(outDir, { recursive: true })
25
- await copyFile('dist/protocol/index.js', `${outDir}/index.js`)
26
-
27
- // Copy all .d.ts files — index.d.ts re-exports from the individual module files,
28
- // so all of them must be present for TypeScript consumers to resolve types.
29
- const distFiles = await readdir('dist/protocol')
30
- for (const file of distFiles) {
31
- if (file.endsWith('.d.ts')) {
32
- await copyFile(`dist/protocol/${file}`, `${outDir}/${file}`)
33
- }
34
- }
35
-
36
- const packageJson = {
37
- name: '@7h3/protocol',
38
- version,
39
- description: '7h3 Protocol: deterministic, signed, replay-safe AI-to-AI message envelopes (wire 7h3/0.1).',
40
- type: 'module',
41
- main: './index.js',
42
- types: './index.d.ts',
43
- exports: {
44
- '.': {
45
- import: './index.js',
46
- types: './index.d.ts',
47
- },
48
- },
49
- files: ['index.js', '*.d.ts', 'README.md'],
50
- license: 'MIT',
51
- repository: {
52
- type: 'git',
53
- url: 'https://github.com/IceMasterT/7h3-protocol-aip.git',
54
- },
55
- }
56
-
57
- const readme = [
58
- '# @7h3/protocol',
59
- '',
60
- '7h3 Protocol (wire version `7h3/0.1`):',
61
- 'deterministic, signed, replay-safe AI-to-AI message envelopes.',
62
- '',
63
- 'Install:',
64
- '',
65
- '```bash',
66
- 'npm install @7h3/protocol',
67
- '```',
68
- '',
69
- 'Import:',
70
- '',
71
- '```ts',
72
- "import { createAipAgentAdapter, receiveEnvelope } from '@7h3/protocol'",
73
- '```',
74
- '',
75
- ].join('\n')
76
-
77
- await writeFile(`${outDir}/package.json`, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8')
78
- await writeFile(`${outDir}/README.md`, readme, 'utf8')
79
-
80
- console.log(`Prepared publishable package in ${outDir}`)
81
- console.log(`Version: ${version}`)
82
- }
83
-
84
- main().catch((error: unknown) => {
85
- const message = error instanceof Error ? error.stack ?? error.message : String(error)
86
- console.error(message)
87
- process.exitCode = 1
88
- })
@@ -1,18 +0,0 @@
1
- import { signCanonicalPayloadHmac, signCanonicalPayloadEd25519 } from '../src/protocol'
2
- import { AIP_V01_CONFORMANCE_VECTORS, AIP_V01_ED25519_CONFORMANCE_VECTORS } from '../src/conformanceVectors'
3
-
4
- async function main() {
5
- console.log('=== HMAC vectors ===')
6
- for (const v of AIP_V01_CONFORMANCE_VECTORS) {
7
- const sig = await signCanonicalPayloadHmac(v.canonical, v.secret)
8
- console.log(`${v.id}: '${sig}'`)
9
- }
10
-
11
- console.log('\n=== Ed25519 vectors ===')
12
- for (const v of AIP_V01_ED25519_CONFORMANCE_VECTORS) {
13
- const sig = await signCanonicalPayloadEd25519(v.canonical, v.privateKey)
14
- console.log(`${v.id}: '${sig}'`)
15
- }
16
- }
17
-
18
- main().catch(e => { console.error(e); process.exit(1) })
@@ -1,19 +0,0 @@
1
- import { spawnSync } from 'node:child_process'
2
-
3
- const commands: Array<[string, string[]]> = [
4
- ['npm', ['run', 'policy:validate']],
5
- ['npm', ['run', 'test']],
6
- ['npm', ['run', 'build:protocol']],
7
- ['npm', ['run', 'lint']],
8
- ['npm', ['run', 'bench:wire:quick']],
9
- ['npm', ['run', 'bench:openloop:adaptive:ci']],
10
- ]
11
-
12
- for (const [command, args] of commands) {
13
- console.log(`\n$ ${command} ${args.join(' ')}`)
14
- const result = spawnSync(command, args, { stdio: 'inherit', shell: false })
15
- if (result.status !== 0) {
16
- process.exitCode = result.status ?? 1
17
- break
18
- }
19
- }
@@ -1,18 +0,0 @@
1
- import { readFile } from 'node:fs/promises'
2
- import { parseRuntimePolicyJson } from '../src/runtimePolicy'
3
-
4
- async function main(): Promise<void> {
5
- const path = process.argv[2] ?? 'AI_RUNTIME_POLICY.json'
6
- const text = await readFile(path, 'utf8')
7
- const policy = parseRuntimePolicyJson(text)
8
- if (!policy.hard_invariants || !policy.slo_defaults || !policy.tuning) {
9
- throw new Error('Runtime policy is missing one or more required sections: hard_invariants, slo_defaults, tuning')
10
- }
11
- console.log(`Runtime policy validated: ${policy.name}@${policy.version} (${policy.status})`)
12
- }
13
-
14
- main().catch((error: unknown) => {
15
- const message = error instanceof Error ? error.stack ?? error.message : String(error)
16
- console.error(message)
17
- process.exitCode = 1
18
- })
@@ -1,162 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import {
3
- generateKeypair,
4
- canonicalizeEnvelope,
5
- createEnvelope,
6
- signEnvelope,
7
- verifyEnvelope,
8
- signRequest,
9
- isEnvelopeExpired,
10
- ENVELOPE_HEADER,
11
- WIRE_VERSION,
12
- type BrowserEnvelopeHeader,
13
- type BrowserEnvelopeBody,
14
- } from './index.ts'
15
-
16
- describe('Browser SDK', () => {
17
- // Test 1: generateKeypair produces non-empty strings
18
- it('generateKeypair produces non-empty strings', async () => {
19
- const kp = await generateKeypair()
20
- expect(typeof kp.publicKey).toBe('string')
21
- expect(kp.publicKey.length).toBeGreaterThan(0)
22
- expect(typeof kp.privateKey).toBe('string')
23
- expect(kp.privateKey.length).toBeGreaterThan(0)
24
- })
25
-
26
- // Test 2: canonicalizeEnvelope matches exact conformance vector
27
- it('canonicalizeEnvelope matches conformance vector', () => {
28
- const header: BrowserEnvelopeHeader = {
29
- version: '7h3/0.1',
30
- messageId: 'vec-1',
31
- nonce: 'nonce-vec-1',
32
- sender: 'agent.alpha',
33
- recipient: 'agent.beta',
34
- timestampMs: 1712500000000,
35
- ttlMs: 60000,
36
- }
37
- const body: BrowserEnvelopeBody = {
38
- intent: 'TASK',
39
- content: 'route:alpha->beta',
40
- capability: 'task.plan',
41
- correlationId: 'corr-1',
42
- }
43
- const expected =
44
- '{"body":{"capability":"task.plan","content":"route:alpha->beta","correlationId":"corr-1","intent":"TASK"},"header":{"messageId":"vec-1","nonce":"nonce-vec-1","recipient":"agent.beta","sender":"agent.alpha","timestampMs":1712500000000,"ttlMs":60000,"version":"7h3/0.1"}}'
45
- expect(canonicalizeEnvelope({ header, body })).toBe(expected)
46
- })
47
-
48
- // Test 3: canonicalizeEnvelope with no optional fields
49
- it('canonicalizeEnvelope omits undefined optional fields', () => {
50
- const header: BrowserEnvelopeHeader = {
51
- version: '7h3/0.1',
52
- messageId: 'msg-1',
53
- nonce: 'n1',
54
- sender: 'agent.x',
55
- timestampMs: 1712500000000,
56
- ttlMs: 30000,
57
- }
58
- const body: BrowserEnvelopeBody = {
59
- intent: 'PING',
60
- content: 'hello',
61
- }
62
- const result = canonicalizeEnvelope({ header, body })
63
- const parsed = JSON.parse(result)
64
- expect(parsed.header.recipient).toBeUndefined()
65
- expect(parsed.body.capability).toBeUndefined()
66
- expect(parsed.body.correlationId).toBeUndefined()
67
- // Verify the raw string doesn't include those keys
68
- expect(result).not.toContain('"recipient"')
69
- expect(result).not.toContain('"capability"')
70
- expect(result).not.toContain('"correlationId"')
71
- })
72
-
73
- // Test 4: createEnvelope produces correct structure
74
- it('createEnvelope produces correct structure', () => {
75
- const env = createEnvelope({
76
- sender: 'agent.test',
77
- body: { intent: 'TASK', content: 'do work' },
78
- })
79
- expect(env.header.version).toBe(WIRE_VERSION)
80
- expect(typeof env.header.messageId).toBe('string')
81
- expect(env.header.messageId.length).toBeGreaterThan(0)
82
- expect(env.body.intent).toBe('TASK')
83
- expect(env.header.sender).toBe('agent.test')
84
- expect(env.header.ttlMs).toBe(60_000)
85
- })
86
-
87
- // Test 5: signEnvelope + verifyEnvelope round trip
88
- it('signEnvelope + verifyEnvelope round trip', async () => {
89
- const kp = await generateKeypair()
90
- const env = createEnvelope({
91
- sender: 'agent.a',
92
- body: { intent: 'PING', content: 'test' },
93
- })
94
- const signed = await signEnvelope(env, kp.privateKey)
95
- expect(signed.signature).toBeDefined()
96
- expect(signed.signature?.alg).toBe('ED25519')
97
- const valid = await verifyEnvelope(signed, kp.publicKey)
98
- expect(valid).toBe(true)
99
- })
100
-
101
- // Test 6: verifyEnvelope: tampered body returns false
102
- it('verifyEnvelope: tampered body returns false', async () => {
103
- const kp = await generateKeypair()
104
- const env = createEnvelope({
105
- sender: 'agent.a',
106
- body: { intent: 'PING', content: 'original' },
107
- })
108
- const signed = await signEnvelope(env, kp.privateKey)
109
- const tampered = {
110
- ...signed,
111
- body: { ...signed.body, content: 'tampered' },
112
- }
113
- const valid = await verifyEnvelope(tampered, kp.publicKey)
114
- expect(valid).toBe(false)
115
- })
116
-
117
- // Test 7: verifyEnvelope: wrong key returns false
118
- it('verifyEnvelope: wrong key returns false', async () => {
119
- const kp1 = await generateKeypair()
120
- const kp2 = await generateKeypair()
121
- const env = createEnvelope({
122
- sender: 'agent.a',
123
- body: { intent: 'PING', content: 'test' },
124
- })
125
- const signed = await signEnvelope(env, kp1.privateKey)
126
- const valid = await verifyEnvelope(signed, kp2.publicKey)
127
- expect(valid).toBe(false)
128
- })
129
-
130
- // Test 8: signRequest: produces Request with x-7h3-envelope header set
131
- it('signRequest: produces Request with x-7h3-envelope header', async () => {
132
- const kp = await generateKeypair()
133
- const req = new Request('https://example.com/api')
134
- const signed = await signRequest(req, {
135
- sender: 'agent.client',
136
- privateKey: kp.privateKey,
137
- })
138
- const headerVal = signed.headers.get(ENVELOPE_HEADER)
139
- expect(headerVal).not.toBeNull()
140
- expect(typeof headerVal).toBe('string')
141
- const parsed = JSON.parse(headerVal!)
142
- expect(parsed.signature).toBeDefined()
143
- expect(parsed.header.sender).toBe('agent.client')
144
- })
145
-
146
- // Test 9: isEnvelopeExpired: returns true for past timestamp
147
- it('isEnvelopeExpired: returns true for past timestamp', () => {
148
- const past = Date.now() - 120_000
149
- const env = {
150
- header: {
151
- version: '7h3/0.1' as const,
152
- messageId: 'x',
153
- nonce: 'y',
154
- sender: 'agent.z',
155
- timestampMs: past,
156
- ttlMs: 60_000,
157
- },
158
- body: { intent: 'PING' as const, content: 'old' },
159
- }
160
- expect(isEnvelopeExpired(env)).toBe(true)
161
- })
162
- })
@@ -1,257 +0,0 @@
1
- // 7h3 Protocol - Browser/Edge SDK
2
- // Pure Web Crypto API. Zero dependencies.
3
- // Works in browsers, Deno, Cloudflare Workers, Bun, and Node 20+.
4
-
5
- export const WIRE_VERSION = '7h3/0.1'
6
- export const ENVELOPE_HEADER = 'x-7h3-envelope'
7
- export const RESPONSE_HEADER = 'x-7h3-response'
8
-
9
- export type IntentKind = 'PING' | 'PONG' | 'CAPS' | 'TASK' | 'RESULT' | 'ERROR'
10
-
11
- export interface BrowserEnvelopeHeader {
12
- version: typeof WIRE_VERSION
13
- messageId: string
14
- timestampMs: number
15
- ttlMs: number
16
- sender: string
17
- recipient?: string
18
- nonce: string
19
- }
20
-
21
- export interface BrowserEnvelopeBody {
22
- intent: IntentKind
23
- content: string
24
- capability?: string
25
- correlationId?: string
26
- }
27
-
28
- export interface BrowserSignature {
29
- alg: 'ED25519'
30
- keyId: string
31
- value: string
32
- }
33
-
34
- export interface BrowserEnvelope {
35
- header: BrowserEnvelopeHeader
36
- body: BrowserEnvelopeBody
37
- signature?: BrowserSignature
38
- }
39
-
40
- export interface BrowserKeyPair {
41
- publicKey: string // base64url SPKI, no padding
42
- privateKey: string // base64url PKCS8, no padding
43
- }
44
-
45
- // ─── Internal helpers (NOT exported) ─────────────────────────────────────────
46
-
47
- function toBase64Url(buf: ArrayBuffer | Uint8Array): string {
48
- const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
49
- let binary = ''
50
- for (let i = 0; i < bytes.length; i++) {
51
- binary += String.fromCharCode(bytes[i])
52
- }
53
- return btoa(binary)
54
- .replace(/\+/g, '-')
55
- .replace(/\//g, '_')
56
- .replace(/=+$/g, '')
57
- }
58
-
59
- function fromBase64Url(str: string): Uint8Array {
60
- const padded = str
61
- .replace(/-/g, '+')
62
- .replace(/_/g, '/')
63
- .padEnd(Math.ceil(str.length / 4) * 4, '=')
64
- const binary = atob(padded)
65
- const bytes = new Uint8Array(binary.length)
66
- for (let i = 0; i < binary.length; i++) {
67
- bytes[i] = binary.charCodeAt(i)
68
- }
69
- return bytes
70
- }
71
-
72
- function generateNonce(): string {
73
- const bytes = new Uint8Array(16)
74
- crypto.getRandomValues(bytes)
75
- return toBase64Url(bytes)
76
- }
77
-
78
- function canonicalBody(b: BrowserEnvelopeBody): string {
79
- const parts: string[] = []
80
- if (b.capability !== undefined) {
81
- parts.push(`"capability":${JSON.stringify(b.capability)}`)
82
- }
83
- parts.push(`"content":${JSON.stringify(b.content)}`)
84
- if (b.correlationId !== undefined) {
85
- parts.push(`"correlationId":${JSON.stringify(b.correlationId)}`)
86
- }
87
- parts.push(`"intent":${JSON.stringify(b.intent)}`)
88
- return `{${parts.join(',')}}`
89
- }
90
-
91
- function canonicalHeader(h: BrowserEnvelopeHeader): string {
92
- const parts: string[] = [
93
- `"messageId":${JSON.stringify(h.messageId)}`,
94
- `"nonce":${JSON.stringify(h.nonce)}`,
95
- ]
96
- if (h.recipient !== undefined) {
97
- parts.push(`"recipient":${JSON.stringify(h.recipient)}`)
98
- }
99
- parts.push(`"sender":${JSON.stringify(h.sender)}`)
100
- parts.push(`"timestampMs":${h.timestampMs}`)
101
- parts.push(`"ttlMs":${h.ttlMs}`)
102
- parts.push(`"version":${JSON.stringify(h.version)}`)
103
- return `{${parts.join(',')}}`
104
- }
105
-
106
- // ─── Public API ───────────────────────────────────────────────────────────────
107
-
108
- export function canonicalizeEnvelope(envelope: Omit<BrowserEnvelope, 'signature'>): string {
109
- return `{"body":${canonicalBody(envelope.body)},"header":${canonicalHeader(envelope.header)}}`
110
- }
111
-
112
- export async function generateKeypair(): Promise<BrowserKeyPair> {
113
- const pair = await crypto.subtle.generateKey(
114
- { name: 'Ed25519' } as AlgorithmIdentifier,
115
- true,
116
- ['sign', 'verify'],
117
- ) as CryptoKeyPair
118
-
119
- const privateKeyRaw = await crypto.subtle.exportKey('pkcs8', pair.privateKey)
120
- const publicKeyRaw = await crypto.subtle.exportKey('spki', pair.publicKey)
121
-
122
- return {
123
- publicKey: toBase64Url(publicKeyRaw),
124
- privateKey: toBase64Url(privateKeyRaw),
125
- }
126
- }
127
-
128
- export async function signEnvelope(
129
- envelope: Omit<BrowserEnvelope, 'signature'>,
130
- privateKeyPkcs8Base64Url: string,
131
- keyId?: string,
132
- ): Promise<BrowserEnvelope> {
133
- const der = fromBase64Url(privateKeyPkcs8Base64Url)
134
- const cryptoKey = await crypto.subtle.importKey(
135
- 'pkcs8',
136
- der.buffer.slice(der.byteOffset, der.byteOffset + der.byteLength) as ArrayBuffer,
137
- { name: 'Ed25519' } as AlgorithmIdentifier,
138
- false,
139
- ['sign'],
140
- )
141
-
142
- const payload = canonicalizeEnvelope(envelope)
143
- const sigBuffer = await crypto.subtle.sign(
144
- 'Ed25519',
145
- cryptoKey,
146
- new TextEncoder().encode(payload),
147
- )
148
-
149
- return {
150
- ...envelope,
151
- signature: {
152
- alg: 'ED25519',
153
- keyId: keyId ?? generateNonce().slice(0, 16),
154
- value: toBase64Url(sigBuffer),
155
- },
156
- }
157
- }
158
-
159
- export async function verifyEnvelope(
160
- envelope: BrowserEnvelope,
161
- publicKeySpkiBase64Url: string,
162
- ): Promise<boolean> {
163
- if (!envelope.signature) return false
164
- if (envelope.signature.alg !== 'ED25519') return false
165
-
166
- const der = fromBase64Url(publicKeySpkiBase64Url)
167
- const cryptoKey = await crypto.subtle.importKey(
168
- 'spki',
169
- der.buffer.slice(der.byteOffset, der.byteOffset + der.byteLength) as ArrayBuffer,
170
- { name: 'Ed25519' } as AlgorithmIdentifier,
171
- false,
172
- ['verify'],
173
- )
174
-
175
- const unsigned: Omit<BrowserEnvelope, 'signature'> = {
176
- header: envelope.header,
177
- body: envelope.body,
178
- }
179
- const payload = canonicalizeEnvelope(unsigned)
180
- const sigBytes = fromBase64Url(envelope.signature.value)
181
-
182
- return crypto.subtle.verify(
183
- 'Ed25519',
184
- cryptoKey,
185
- sigBytes.buffer.slice(sigBytes.byteOffset, sigBytes.byteOffset + sigBytes.byteLength) as ArrayBuffer,
186
- new TextEncoder().encode(payload),
187
- )
188
- }
189
-
190
- export function createEnvelope(opts: {
191
- sender: string
192
- recipient?: string
193
- ttlMs?: number
194
- body: BrowserEnvelopeBody
195
- }): Omit<BrowserEnvelope, 'signature'> {
196
- return {
197
- header: {
198
- version: WIRE_VERSION,
199
- messageId: generateNonce(),
200
- timestampMs: Date.now(),
201
- ttlMs: opts.ttlMs ?? 60_000,
202
- sender: opts.sender,
203
- recipient: opts.recipient,
204
- nonce: generateNonce(),
205
- },
206
- body: opts.body,
207
- }
208
- }
209
-
210
- export async function signRequest(
211
- request: Request,
212
- opts: {
213
- sender: string
214
- recipient?: string
215
- ttlMs?: number
216
- privateKey: string
217
- keyId?: string
218
- },
219
- ): Promise<Request> {
220
- const envelope = createEnvelope({
221
- sender: opts.sender,
222
- recipient: opts.recipient,
223
- ttlMs: opts.ttlMs,
224
- body: {
225
- intent: 'TASK',
226
- content: request.url,
227
- },
228
- })
229
-
230
- const signed = await signEnvelope(envelope, opts.privateKey, opts.keyId)
231
-
232
- const headers = new Headers(request.headers)
233
- headers.set(ENVELOPE_HEADER, JSON.stringify(signed))
234
-
235
- return new Request(request, { headers })
236
- }
237
-
238
- export async function verifyResponseHeader(
239
- response: Response,
240
- publicKey: string,
241
- ): Promise<boolean> {
242
- const headerValue = response.headers.get(RESPONSE_HEADER)
243
- if (!headerValue) return false
244
-
245
- let parsed: BrowserEnvelope
246
- try {
247
- parsed = JSON.parse(headerValue) as BrowserEnvelope
248
- } catch {
249
- return false
250
- }
251
-
252
- return verifyEnvelope(parsed, publicKey)
253
- }
254
-
255
- export function isEnvelopeExpired(envelope: BrowserEnvelope): boolean {
256
- return envelope.header.timestampMs + envelope.header.ttlMs < Date.now()
257
- }
@@ -1,13 +0,0 @@
1
- {
2
- "name": "@7h3/protocol-browser",
3
- "version": "0.5.0",
4
- "description": "7h3 Protocol - Browser/Edge SDK. Pure Web Crypto API. Zero dependencies.",
5
- "type": "module",
6
- "main": "./index.js",
7
- "module": "./index.js",
8
- "types": "./index.d.ts",
9
- "exports": { ".": { "types": "./index.d.ts", "import": "./index.js" } },
10
- "keywords": ["7h3","protocol","browser","webcrypto","ed25519","signing","mcp"],
11
- "license": "MIT",
12
- "sideEffects": false
13
- }