llmtxt 2026.4.5 → 2026.4.7
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/CHANGELOG.md +9 -0
- package/README.md +242 -54
- package/dist/__tests__/a2a.test.d.ts +14 -0
- package/dist/__tests__/a2a.test.d.ts.map +1 -0
- package/dist/__tests__/a2a.test.js +217 -0
- package/dist/__tests__/a2a.test.js.map +1 -0
- package/dist/__tests__/backend-contract.test.d.ts +18 -7
- package/dist/__tests__/backend-contract.test.d.ts.map +1 -1
- package/dist/__tests__/backend-contract.test.js +634 -29
- package/dist/__tests__/backend-contract.test.js.map +1 -1
- package/dist/__tests__/backend-factory.test.d.ts +18 -0
- package/dist/__tests__/backend-factory.test.d.ts.map +1 -0
- package/dist/__tests__/backend-factory.test.js +254 -0
- package/dist/__tests__/backend-factory.test.js.map +1 -0
- package/dist/__tests__/blob-5-agent-hub-spoke.test.d.ts +26 -0
- package/dist/__tests__/blob-5-agent-hub-spoke.test.d.ts.map +1 -0
- package/dist/__tests__/blob-5-agent-hub-spoke.test.js +262 -0
- package/dist/__tests__/blob-5-agent-hub-spoke.test.js.map +1 -0
- package/dist/__tests__/blob-backend.test.d.ts +16 -0
- package/dist/__tests__/blob-backend.test.d.ts.map +1 -0
- package/dist/__tests__/blob-backend.test.js +271 -0
- package/dist/__tests__/blob-backend.test.js.map +1 -0
- package/dist/__tests__/blob-changeset.test.d.ts +10 -0
- package/dist/__tests__/blob-changeset.test.d.ts.map +1 -0
- package/dist/__tests__/blob-changeset.test.js +286 -0
- package/dist/__tests__/blob-changeset.test.js.map +1 -0
- package/dist/__tests__/blob-cli.test.d.ts +20 -0
- package/dist/__tests__/blob-cli.test.d.ts.map +1 -0
- package/dist/__tests__/blob-cli.test.js +178 -0
- package/dist/__tests__/blob-cli.test.js.map +1 -0
- package/dist/__tests__/blob-fs-adapter.test.d.ts +16 -0
- package/dist/__tests__/blob-fs-adapter.test.d.ts.map +1 -0
- package/dist/__tests__/blob-fs-adapter.test.js +385 -0
- package/dist/__tests__/blob-fs-adapter.test.js.map +1 -0
- package/dist/__tests__/crdt-primitives.test.d.ts +20 -0
- package/dist/__tests__/crdt-primitives.test.d.ts.map +1 -0
- package/dist/__tests__/crdt-primitives.test.js +255 -0
- package/dist/__tests__/crdt-primitives.test.js.map +1 -0
- package/dist/__tests__/crdt-sdk.test.d.ts +30 -0
- package/dist/__tests__/crdt-sdk.test.d.ts.map +1 -0
- package/dist/__tests__/crdt-sdk.test.js +380 -0
- package/dist/__tests__/crdt-sdk.test.js.map +1 -0
- package/dist/__tests__/crsqlite-loader.test.d.ts +15 -0
- package/dist/__tests__/crsqlite-loader.test.d.ts.map +1 -0
- package/dist/__tests__/crsqlite-loader.test.js +116 -0
- package/dist/__tests__/crsqlite-loader.test.js.map +1 -0
- package/dist/__tests__/discovery.test.d.ts +15 -0
- package/dist/__tests__/discovery.test.d.ts.map +1 -0
- package/dist/__tests__/discovery.test.js +174 -0
- package/dist/__tests__/discovery.test.js.map +1 -0
- package/dist/__tests__/export-backend.test.d.ts +15 -0
- package/dist/__tests__/export-backend.test.d.ts.map +1 -0
- package/dist/__tests__/export-backend.test.js +316 -0
- package/dist/__tests__/export-backend.test.js.map +1 -0
- package/dist/__tests__/export-determinism.test.d.ts +19 -0
- package/dist/__tests__/export-determinism.test.d.ts.map +1 -0
- package/dist/__tests__/export-determinism.test.js +253 -0
- package/dist/__tests__/export-determinism.test.js.map +1 -0
- package/dist/__tests__/export.test.d.ts +11 -0
- package/dist/__tests__/export.test.d.ts.map +1 -0
- package/dist/__tests__/export.test.js +297 -0
- package/dist/__tests__/export.test.js.map +1 -0
- package/dist/__tests__/helpers/test-pg.d.ts +150 -0
- package/dist/__tests__/helpers/test-pg.d.ts.map +1 -0
- package/dist/__tests__/helpers/test-pg.js +836 -0
- package/dist/__tests__/helpers/test-pg.js.map +1 -0
- package/dist/__tests__/hub-spoke-topology.test.d.ts +24 -0
- package/dist/__tests__/hub-spoke-topology.test.d.ts.map +1 -0
- package/dist/__tests__/hub-spoke-topology.test.js +299 -0
- package/dist/__tests__/hub-spoke-topology.test.js.map +1 -0
- package/dist/__tests__/local-backend-crr.test.d.ts +25 -0
- package/dist/__tests__/local-backend-crr.test.d.ts.map +1 -0
- package/dist/__tests__/local-backend-crr.test.js +197 -0
- package/dist/__tests__/local-backend-crr.test.js.map +1 -0
- package/dist/__tests__/local-backend-sync.test.d.ts +20 -0
- package/dist/__tests__/local-backend-sync.test.d.ts.map +1 -0
- package/dist/__tests__/local-backend-sync.test.js +373 -0
- package/dist/__tests__/local-backend-sync.test.js.map +1 -0
- package/dist/__tests__/local-multi-agent.test.d.ts +20 -0
- package/dist/__tests__/local-multi-agent.test.d.ts.map +1 -0
- package/dist/__tests__/local-multi-agent.test.js +229 -0
- package/dist/__tests__/local-multi-agent.test.js.map +1 -0
- package/dist/__tests__/loro-crsqlite-integration.test.d.ts +32 -0
- package/dist/__tests__/loro-crsqlite-integration.test.d.ts.map +1 -0
- package/dist/__tests__/loro-crsqlite-integration.test.js +340 -0
- package/dist/__tests__/loro-crsqlite-integration.test.js.map +1 -0
- package/dist/__tests__/mesh-5-peer.test.d.ts +35 -0
- package/dist/__tests__/mesh-5-peer.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-5-peer.test.js +435 -0
- package/dist/__tests__/mesh-5-peer.test.js.map +1 -0
- package/dist/__tests__/mesh-cli.test.d.ts +18 -0
- package/dist/__tests__/mesh-cli.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-cli.test.js +143 -0
- package/dist/__tests__/mesh-cli.test.js.map +1 -0
- package/dist/__tests__/presence.test.d.ts +13 -0
- package/dist/__tests__/presence.test.d.ts.map +1 -0
- package/dist/__tests__/presence.test.js +198 -0
- package/dist/__tests__/presence.test.js.map +1 -0
- package/dist/__tests__/session-crash-recovery.test.d.ts +28 -0
- package/dist/__tests__/session-crash-recovery.test.d.ts.map +1 -0
- package/dist/__tests__/session-crash-recovery.test.js +689 -0
- package/dist/__tests__/session-crash-recovery.test.js.map +1 -0
- package/dist/__tests__/session-swarm.test.d.ts +35 -0
- package/dist/__tests__/session-swarm.test.d.ts.map +1 -0
- package/dist/__tests__/session-swarm.test.js +734 -0
- package/dist/__tests__/session-swarm.test.js.map +1 -0
- package/dist/__tests__/session.test.d.ts +13 -0
- package/dist/__tests__/session.test.d.ts.map +1 -0
- package/dist/__tests__/session.test.js +1187 -0
- package/dist/__tests__/session.test.js.map +1 -0
- package/dist/__tests__/standalone-topology.test.d.ts +18 -0
- package/dist/__tests__/standalone-topology.test.d.ts.map +1 -0
- package/dist/__tests__/standalone-topology.test.js +297 -0
- package/dist/__tests__/standalone-topology.test.js.map +1 -0
- package/dist/__tests__/sync-engine.test.d.ts +15 -0
- package/dist/__tests__/sync-engine.test.d.ts.map +1 -0
- package/dist/__tests__/sync-engine.test.js +286 -0
- package/dist/__tests__/sync-engine.test.js.map +1 -0
- package/dist/__tests__/topology-failure.test.d.ts +23 -0
- package/dist/__tests__/topology-failure.test.d.ts.map +1 -0
- package/dist/__tests__/topology-failure.test.js +357 -0
- package/dist/__tests__/topology-failure.test.js.map +1 -0
- package/dist/__tests__/topology.test.d.ts +17 -0
- package/dist/__tests__/topology.test.d.ts.map +1 -0
- package/dist/__tests__/topology.test.js +346 -0
- package/dist/__tests__/topology.test.js.map +1 -0
- package/dist/__tests__/transport.test.d.ts +18 -0
- package/dist/__tests__/transport.test.d.ts.map +1 -0
- package/dist/__tests__/transport.test.js +305 -0
- package/dist/__tests__/transport.test.js.map +1 -0
- package/dist/backend/factory.d.ts +379 -0
- package/dist/backend/factory.d.ts.map +1 -0
- package/dist/backend/factory.js +824 -0
- package/dist/backend/factory.js.map +1 -0
- package/dist/cli/llmtxt.js +1232 -8
- package/dist/cli/llmtxt.js.map +1 -1
- package/dist/compression.d.ts +1 -1
- package/dist/compression.d.ts.map +1 -1
- package/dist/compression.js +1 -1
- package/dist/compression.js.map +1 -1
- package/dist/core/backend.d.ts +678 -2
- package/dist/core/backend.d.ts.map +1 -1
- package/dist/core/backend.js +16 -1
- package/dist/core/backend.js.map +1 -1
- package/dist/core/errors.d.ts +59 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +81 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/crdt-primitives.d.ts +87 -45
- package/dist/crdt-primitives.d.ts.map +1 -1
- package/dist/crdt-primitives.js +140 -94
- package/dist/crdt-primitives.js.map +1 -1
- package/dist/crdt.d.ts +58 -13
- package/dist/crdt.d.ts.map +1 -1
- package/dist/crdt.js +140 -67
- package/dist/crdt.js.map +1 -1
- package/dist/crsqlite-loader.d.ts +35 -0
- package/dist/crsqlite-loader.d.ts.map +1 -0
- package/dist/crsqlite-loader.js +56 -0
- package/dist/crsqlite-loader.js.map +1 -0
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +9 -4
- package/dist/embeddings.js.map +1 -1
- package/dist/export/backend-export.d.ts +58 -0
- package/dist/export/backend-export.d.ts.map +1 -0
- package/dist/export/backend-export.js +193 -0
- package/dist/export/backend-export.js.map +1 -0
- package/dist/export/canonical.d.ts +69 -0
- package/dist/export/canonical.d.ts.map +1 -0
- package/dist/export/canonical.js +82 -0
- package/dist/export/canonical.js.map +1 -0
- package/dist/export/import-parser.d.ts +36 -0
- package/dist/export/import-parser.d.ts.map +1 -0
- package/dist/export/import-parser.js +209 -0
- package/dist/export/import-parser.js.map +1 -0
- package/dist/export/index.d.ts +17 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +17 -0
- package/dist/export/index.js.map +1 -0
- package/dist/export/json.d.ts +52 -0
- package/dist/export/json.d.ts.map +1 -0
- package/dist/export/json.js +103 -0
- package/dist/export/json.js.map +1 -0
- package/dist/export/llmtxt.d.ts +56 -0
- package/dist/export/llmtxt.d.ts.map +1 -0
- package/dist/export/llmtxt.js +110 -0
- package/dist/export/llmtxt.js.map +1 -0
- package/dist/export/markdown.d.ts +36 -0
- package/dist/export/markdown.d.ts.map +1 -0
- package/dist/export/markdown.js +67 -0
- package/dist/export/markdown.js.map +1 -0
- package/dist/export/txt.d.ts +29 -0
- package/dist/export/txt.d.ts.map +1 -0
- package/dist/export/txt.js +33 -0
- package/dist/export/txt.js.map +1 -0
- package/dist/export/types.d.ts +76 -0
- package/dist/export/types.d.ts.map +1 -0
- package/dist/export/types.js +11 -0
- package/dist/export/types.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/local/blob-changeset.d.ts +106 -0
- package/dist/local/blob-changeset.d.ts.map +1 -0
- package/dist/local/blob-changeset.js +169 -0
- package/dist/local/blob-changeset.js.map +1 -0
- package/dist/local/blob-fs-adapter.d.ts +86 -0
- package/dist/local/blob-fs-adapter.d.ts.map +1 -0
- package/dist/local/blob-fs-adapter.js +293 -0
- package/dist/local/blob-fs-adapter.js.map +1 -0
- package/dist/local/local-backend.d.ts +157 -2
- package/dist/local/local-backend.d.ts.map +1 -1
- package/dist/local/local-backend.js +829 -20
- package/dist/local/local-backend.js.map +1 -1
- package/dist/local/migrations/20260417220000_crdt_state_rename/migration.sql +15 -0
- package/dist/local/migrations/20260417220000_crdt_state_rename/snapshot.json +1594 -0
- package/dist/local/migrations/20260417230000_crsql_as_crr/migration.sql +45 -0
- package/dist/local/migrations/20260417230000_crsql_as_crr/snapshot.json +1593 -0
- package/dist/local/migrations/20260417240000_blob_attachments/migration.sql +54 -0
- package/dist/local/schema-local.d.ts +162 -1
- package/dist/local/schema-local.d.ts.map +1 -1
- package/dist/local/schema-local.js +44 -1
- package/dist/local/schema-local.js.map +1 -1
- package/dist/mesh/a2a.d.ts +93 -0
- package/dist/mesh/a2a.d.ts.map +1 -0
- package/dist/mesh/a2a.js +326 -0
- package/dist/mesh/a2a.js.map +1 -0
- package/dist/mesh/discovery.d.ts +134 -0
- package/dist/mesh/discovery.d.ts.map +1 -0
- package/dist/mesh/discovery.js +290 -0
- package/dist/mesh/discovery.js.map +1 -0
- package/dist/mesh/index.d.ts +16 -0
- package/dist/mesh/index.d.ts.map +1 -0
- package/dist/mesh/index.js +16 -0
- package/dist/mesh/index.js.map +1 -0
- package/dist/mesh/presence.d.ts +94 -0
- package/dist/mesh/presence.d.ts.map +1 -0
- package/dist/mesh/presence.js +219 -0
- package/dist/mesh/presence.js.map +1 -0
- package/dist/mesh/server-peer-adapter.d.ts +248 -0
- package/dist/mesh/server-peer-adapter.d.ts.map +1 -0
- package/dist/mesh/server-peer-adapter.js +269 -0
- package/dist/mesh/server-peer-adapter.js.map +1 -0
- package/dist/mesh/sync-engine.d.ts +116 -0
- package/dist/mesh/sync-engine.d.ts.map +1 -0
- package/dist/mesh/sync-engine.js +349 -0
- package/dist/mesh/sync-engine.js.map +1 -0
- package/dist/mesh/transport.d.ts +196 -0
- package/dist/mesh/transport.d.ts.map +1 -0
- package/dist/mesh/transport.js +795 -0
- package/dist/mesh/transport.js.map +1 -0
- package/dist/pg/index.d.ts +11 -0
- package/dist/pg/index.d.ts.map +1 -0
- package/dist/pg/index.js +10 -0
- package/dist/pg/index.js.map +1 -0
- package/dist/pg/pg-backend.d.ts +434 -0
- package/dist/pg/pg-backend.d.ts.map +1 -0
- package/dist/pg/pg-backend.js +2749 -0
- package/dist/pg/pg-backend.js.map +1 -0
- package/dist/remote/remote-backend.d.ts +82 -2
- package/dist/remote/remote-backend.d.ts.map +1 -1
- package/dist/remote/remote-backend.js +374 -2
- package/dist/remote/remote-backend.js.map +1 -1
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +1 -0
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/session.d.ts +285 -0
- package/dist/sdk/session.d.ts.map +1 -0
- package/dist/sdk/session.js +403 -0
- package/dist/sdk/session.js.map +1 -0
- package/dist/topology.d.ts +210 -0
- package/dist/topology.d.ts.map +1 -0
- package/dist/topology.js +153 -0
- package/dist/topology.js.map +1 -0
- package/dist/wasm.d.ts +8 -0
- package/dist/wasm.d.ts.map +1 -1
- package/dist/wasm.js +10 -0
- package/dist/wasm.js.map +1 -1
- package/package.json +32 -7
- package/wasm/README.md +61 -5
- package/wasm/llmtxt_core.d.ts +130 -0
- package/wasm/llmtxt_core.js +238 -0
- package/wasm/llmtxt_core_bg.wasm +0 -0
- package/wasm/llmtxt_core_bg.wasm.d.ts +35 -26
- package/wasm/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2026.4.7] — 2026-04-17
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Bundler compatibility for `onnxruntime-node`**: dynamic import in `embeddings.ts` now uses a runtime-constructed specifier + `/* @vite-ignore */` + `/* webpackIgnore: true */` hints. esbuild, webpack, vite, and rollup no longer try to inline the `.node` native addon. Verified with esbuild 0.28 bundle of `llmtxt` + `llmtxt/embeddings` — exit 0, no `--external` flag needed for the onnxruntime path.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- `better-sqlite3`, `drizzle-orm`, `postgres` moved from `optionalDependencies` to `peerDependencies` + `peerDependenciesMeta.optional: true`. pnpm no longer auto-installs them — consumers must opt in per topology. Matches treatment of `onnxruntime-node` and `@vlcn.io/crsqlite`.
|
|
17
|
+
- README adds install matrix + esbuild/webpack/vite externalize list.
|
|
18
|
+
|
|
10
19
|
## [2026.4.5] - 2026-04-16
|
|
11
20
|
|
|
12
21
|
This release ships the full Round 1+2+3 multi-agent foundation: CRDT/Yrs, signed Ed25519 identity, append-only event log, real-time presence/leases/diff-subscriptions (W1+W2), BFT consensus, agent scratchpad, A2A envelope routing (W3), a self-hosted observability stack (Grafana / Loki / Tempo / Prometheus / OTel collector / GlitchTip on Railway), OpenAPI schema generation with forge-ts integration, local semantic embeddings via pgvector + ONNX, four reference agents plus a `/demo` page, and a fully portable SDK offering `LocalBackend`, `RemoteBackend`, and `llmtxt` CLI — including a complete CLEO integration example. Also upgrades drizzle-orm/kit to `1.0.0-beta.21` and zod to `^4`.
|
package/README.md
CHANGED
|
@@ -1,16 +1,219 @@
|
|
|
1
1
|
# llmtxt
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/llmtxt)
|
|
4
|
+
|
|
3
5
|
Primitives and SDK for LLM agent content workflows.
|
|
4
6
|
|
|
5
7
|
`llmtxt` wraps the Rust `llmtxt-core` crate through WASM so TypeScript
|
|
6
8
|
consumers use the same single-source-of-truth logic as native Rust consumers.
|
|
7
9
|
|
|
10
|
+
**v2026.4.7** (patch): bundler-friendly dynamic import of `onnxruntime-node`; `drizzle-orm` / `better-sqlite3` / `postgres` moved from `optionalDependencies` to optional `peerDependencies` so consumers no longer auto-install them. Docs add the required externalize list for esbuild / webpack / vite / rollup.
|
|
11
|
+
|
|
12
|
+
**v2026.4.6**: Loro CRDT (replaces Yrs — binary-incompatible), AgentSession lifecycle, document export/import (4 formats), binary blob attachments, `createBackend()` topology factory, cr-sqlite changeset sync, P2P mesh, and new CLI commands.
|
|
13
|
+
|
|
8
14
|
## Install
|
|
9
15
|
|
|
10
16
|
```bash
|
|
11
17
|
npm install llmtxt
|
|
12
18
|
```
|
|
13
19
|
|
|
20
|
+
All database/embedding drivers are **optional peer dependencies** — install only the ones your topology needs:
|
|
21
|
+
|
|
22
|
+
| Topology / feature | Extra install |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `standalone` (local SQLite) | `pnpm add better-sqlite3 drizzle-orm` |
|
|
25
|
+
| `hub-spoke` (Postgres hub) | `pnpm add postgres drizzle-orm` |
|
|
26
|
+
| `mesh` + cr-sqlite CRR | `pnpm add @vlcn.io/crsqlite` |
|
|
27
|
+
| Semantic embeddings | `pnpm add onnxruntime-node` |
|
|
28
|
+
| RemoteBackend-only consumer (no local DB) | nothing extra |
|
|
29
|
+
|
|
30
|
+
## Bundling with esbuild / webpack / vite / rollup
|
|
31
|
+
|
|
32
|
+
`llmtxt` keeps optional peer deps opaque to static bundler analysis where possible, but deep imports inside `LocalBackend` (drizzle-orm) and native addons (onnxruntime-node) must be marked **external** by consumers who bundle. Minimum external list:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
// esbuild
|
|
36
|
+
esbuild.build({
|
|
37
|
+
bundle: true,
|
|
38
|
+
platform: 'node',
|
|
39
|
+
external: [
|
|
40
|
+
'onnxruntime-node', // native .node addon
|
|
41
|
+
'better-sqlite3', // native .node addon
|
|
42
|
+
'@vlcn.io/crsqlite', // native extension + ESM-only
|
|
43
|
+
'drizzle-orm', // transitively pulls mssql, @opentelemetry/api
|
|
44
|
+
'drizzle-orm/*', // subpath imports
|
|
45
|
+
'postgres',
|
|
46
|
+
'mssql',
|
|
47
|
+
'@opentelemetry/api',
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Same list works as `externals` in webpack/rollup and `build.rollupOptions.external` in vite. If your deployment does NOT use LocalBackend (e.g. RemoteBackend only), you may also externalize `llmtxt/local`.
|
|
53
|
+
|
|
54
|
+
## Topology Factory
|
|
55
|
+
|
|
56
|
+
The entry point for all deployments. Returns a `Backend` configured for the chosen topology.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { createBackend } from 'llmtxt';
|
|
60
|
+
|
|
61
|
+
// Standalone — local SQLite, no network
|
|
62
|
+
const backend = await createBackend({ topology: 'standalone', storagePath: './.llmtxt' });
|
|
63
|
+
|
|
64
|
+
// Hub-spoke — ephemeral worker pointing at shared hub
|
|
65
|
+
const backend2 = await createBackend({
|
|
66
|
+
topology: 'hub-spoke',
|
|
67
|
+
hubUrl: 'https://api.llmtxt.my',
|
|
68
|
+
apiKey: process.env.LLMTXT_API_KEY,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Mesh — P2P, no server required
|
|
72
|
+
const backend3 = await createBackend({
|
|
73
|
+
topology: 'mesh',
|
|
74
|
+
storagePath: './.llmtxt',
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Note: `createBackend` is `async` (returns `Promise<Backend>`). Always `await` it.
|
|
79
|
+
|
|
80
|
+
See [docs.llmtxt.my/architecture/topology](https://docs.llmtxt.my/architecture/topology) and [docs/specs/ARCH-T429-hub-spoke-topology.md](../../docs/specs/ARCH-T429-hub-spoke-topology.md).
|
|
81
|
+
|
|
82
|
+
## AgentSession Lifecycle
|
|
83
|
+
|
|
84
|
+
Gives every agent an explicit, auditable lifecycle with crash recovery and signed contribution receipts.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { AgentSession } from 'llmtxt/sdk';
|
|
88
|
+
import type { ContributionReceipt } from 'llmtxt/sdk';
|
|
89
|
+
|
|
90
|
+
const session = new AgentSession({ backend, agentId: 'agent-1' });
|
|
91
|
+
await session.open(); // registers presence, allocates temp .db for LocalBackend sessions
|
|
92
|
+
|
|
93
|
+
// contribute() returns T (whatever fn returns); receipt is from close()
|
|
94
|
+
const doc = await session.contribute(async (b) => {
|
|
95
|
+
const created = await b.createDocument({ title: 'Spec', createdBy: 'agent-1' });
|
|
96
|
+
await b.publishVersion({
|
|
97
|
+
documentId: created.id,
|
|
98
|
+
content: '# Spec',
|
|
99
|
+
patchText: '',
|
|
100
|
+
createdBy: 'agent-1',
|
|
101
|
+
changelog: 'Initial',
|
|
102
|
+
});
|
|
103
|
+
return created;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const contributionReceipt: ContributionReceipt = await session.close();
|
|
107
|
+
// Releases leases, drains inbox, deletes temp .db, emits signed ContributionReceipt
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`ContributionReceipt` fields: `sessionId`, `agentId`, `documentIds`, `eventCount`, `sessionDurationMs`, `openedAt`, `closedAt`, `signature` (Ed25519 when RemoteBackend).
|
|
111
|
+
|
|
112
|
+
See [docs.llmtxt.my/multi-agent/session-lifecycle](https://docs.llmtxt.my/multi-agent/session-lifecycle) and [docs/specs/ARCH-T426-ephemeral-agent-lifecycle.md](../../docs/specs/ARCH-T426-ephemeral-agent-lifecycle.md).
|
|
113
|
+
|
|
114
|
+
## Document Export / Import
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// Export a document to disk
|
|
118
|
+
const result = await backend.exportDocument({
|
|
119
|
+
slug: 'my-spec',
|
|
120
|
+
format: 'markdown', // 'markdown' | 'json' | 'txt' | 'llmtxt'
|
|
121
|
+
outputPath: './exports/my-spec.md',
|
|
122
|
+
sign: true, // Ed25519-sign the export manifest
|
|
123
|
+
});
|
|
124
|
+
// result: { filePath, slug, version, fileHash, byteCount, exportedAt, signatureHex }
|
|
125
|
+
|
|
126
|
+
// Export all documents
|
|
127
|
+
const allResult = await backend.exportAll({ format: 'json', outputDir: './exports/' });
|
|
128
|
+
|
|
129
|
+
// Import from file — creates doc or appends new version if slug exists
|
|
130
|
+
const imported = await backend.importDocument({
|
|
131
|
+
filePath: './exports/my-spec.md',
|
|
132
|
+
importedBy: 'agent-1',
|
|
133
|
+
onConflict: 'new_version', // 'new_version' | 'create'
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Formats: `markdown` (YAML frontmatter + body), `json` (structured), `txt` (body only), `llmtxt` (round-trippable with chain reference). Output is deterministic: same document state always produces identical file bytes.
|
|
138
|
+
|
|
139
|
+
See [docs.llmtxt.my/sdk/export-import](https://docs.llmtxt.my/sdk/export-import) and [docs/specs/ARCH-T427-document-export-ssot.md](../../docs/specs/ARCH-T427-document-export-ssot.md).
|
|
140
|
+
|
|
141
|
+
## Binary Blob Attachments
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import * as fs from 'node:fs';
|
|
145
|
+
|
|
146
|
+
// Attach a binary file to a document
|
|
147
|
+
const attachment = await backend.attachBlob({
|
|
148
|
+
docSlug: 'my-spec',
|
|
149
|
+
name: 'diagram.png',
|
|
150
|
+
data: fs.readFileSync('./diagram.png'),
|
|
151
|
+
contentType: 'image/png',
|
|
152
|
+
uploadedBy: 'agent-1',
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Read back — hash verified on every read when includeData=true
|
|
156
|
+
const blob = await backend.getBlob('my-spec', 'diagram.png', { includeData: true });
|
|
157
|
+
|
|
158
|
+
// List attachments (metadata only, no bytes)
|
|
159
|
+
const blobs = await backend.listBlobs('my-spec');
|
|
160
|
+
|
|
161
|
+
// Remove
|
|
162
|
+
await backend.detachBlob('my-spec', 'diagram.png', 'agent-1');
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Blobs are content-addressed (SHA-256). Hash verification is mandatory on read — corrupt bytes are never returned. Max default size: 100 MB. Conflict resolution: Last Write Wins per attachment name.
|
|
166
|
+
|
|
167
|
+
See [docs.llmtxt.my/sdk/blob-attachments](https://docs.llmtxt.my/sdk/blob-attachments) and [docs/specs/ARCH-T428-binary-blob-attachments.md](../../docs/specs/ARCH-T428-binary-blob-attachments.md).
|
|
168
|
+
|
|
169
|
+
## cr-sqlite LocalBackend (Changeset Sync)
|
|
170
|
+
|
|
171
|
+
Install the optional peer dependency to enable changeset-based sync between LocalBackend instances:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm install @vlcn.io/crsqlite
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { createBackend } from 'llmtxt';
|
|
179
|
+
|
|
180
|
+
const backend = await createBackend({
|
|
181
|
+
topology: 'standalone',
|
|
182
|
+
storagePath: './.llmtxt',
|
|
183
|
+
crsqlite: true, // requires @vlcn.io/crsqlite peer dep
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Exchange changesets with another agent
|
|
187
|
+
const changes = await backend.getChangesSince({ version: lastSyncVersion });
|
|
188
|
+
await otherBackend.applyChanges({ changes });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Single-tenant only (one agent per `.db`). Loro CRDT state in the `crdt_state` column is merged at the application level (not via cr-sqlite row merge). See [docs/specs/P2-cr-sqlite.md](../../docs/specs/P2-cr-sqlite.md).
|
|
192
|
+
|
|
193
|
+
## P2P Mesh
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import { createBackend } from 'llmtxt';
|
|
197
|
+
|
|
198
|
+
const backend = await createBackend({
|
|
199
|
+
topology: 'mesh',
|
|
200
|
+
storagePath: './.llmtxt',
|
|
201
|
+
peers: ['unix:/tmp/agent-b.sock', 'http://192.168.1.5:7642'],
|
|
202
|
+
});
|
|
203
|
+
await backend.open();
|
|
204
|
+
// Sync engine starts; Ed25519 mutual handshake required for each peer connection
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
See [docs.llmtxt.my/mesh](https://docs.llmtxt.my/mesh) and [docs/specs/P3-p2p-mesh.md](../../docs/specs/P3-p2p-mesh.md).
|
|
208
|
+
|
|
209
|
+
## Loro CRDT (replaces Yrs)
|
|
210
|
+
|
|
211
|
+
v2026.4.6 replaced `yrs` with `loro` 1.0 in `crates/llmtxt-core`. The six WASM function names are unchanged (`crdt_new_doc`, `crdt_encode_state_as_update`, `crdt_apply_update`, `crdt_merge_updates`, `crdt_state_vector`, `crdt_diff_update`) but their binary format is incompatible with previous versions.
|
|
212
|
+
|
|
213
|
+
**Wire protocol change**: 1-byte message prefix `0x01`/`0x02`/`0x03`/`0x04` replaces the y-sync `0x00`/`0x01`/`0x02`/`0x03` framing. Legacy Yjs clients will be rejected.
|
|
214
|
+
|
|
215
|
+
**Migration**: No data migration path. Drop all `section_crdt_states` and `section_crdt_updates` rows on deploy. See [docs/specs/P1-loro-migration.md](../../docs/specs/P1-loro-migration.md).
|
|
216
|
+
|
|
14
217
|
## Primitives
|
|
15
218
|
|
|
16
219
|
```ts
|
|
@@ -27,16 +230,9 @@ const hash = hashContent(text);
|
|
|
27
230
|
|
|
28
231
|
const patch = createPatch('hello\n', 'hello world\n');
|
|
29
232
|
const rebuilt = applyPatch('hello\n', patch);
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Multi-Way Diff and Cherry-Pick Merge
|
|
33
233
|
|
|
34
|
-
|
|
35
|
-
import { multiWayDiff, cherryPickMerge } from 'llmtxt';
|
|
36
|
-
|
|
37
|
-
// Compare multiple agent versions against a base using LCS alignment
|
|
234
|
+
// LCS-aligned multi-way diff across agent versions
|
|
38
235
|
const diff = multiWayDiff(base, JSON.stringify([v2Content, v3Content, v4Content]));
|
|
39
|
-
// Returns MultiDiffResult: { sections, totalVersions, baseTokenCount }
|
|
40
236
|
|
|
41
237
|
// Selectively merge sections from different versions
|
|
42
238
|
const merged = cherryPickMerge(
|
|
@@ -47,80 +243,72 @@ const merged = cherryPickMerge(
|
|
|
47
243
|
{ section: 'API Reference', fromVersion: 2 },
|
|
48
244
|
])
|
|
49
245
|
);
|
|
50
|
-
// Returns CherryPickResult: { content, provenance, stats }
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## SDK (Collaborative Documents)
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import {
|
|
57
|
-
isValidTransition, evaluateApprovals, planRetrieval,
|
|
58
|
-
reconstructVersion, attributeVersion, buildContributorSummary,
|
|
59
|
-
} from 'llmtxt/sdk';
|
|
60
246
|
```
|
|
61
247
|
|
|
62
|
-
|
|
248
|
+
## Subpath Exports
|
|
63
249
|
|
|
64
250
|
```ts
|
|
251
|
+
import { AgentSession } from 'llmtxt/sdk';
|
|
252
|
+
import { createBackend } from 'llmtxt/topology';
|
|
253
|
+
import { LocalBackend } from 'llmtxt/local';
|
|
254
|
+
import { RemoteBackend } from 'llmtxt/remote';
|
|
65
255
|
import { generateOverview, getSection } from 'llmtxt/disclosure';
|
|
66
256
|
import { textSimilarity, rankBySimilarity } from 'llmtxt/similarity';
|
|
67
257
|
import { buildGraph } from 'llmtxt/graph';
|
|
68
258
|
```
|
|
69
259
|
|
|
70
|
-
##
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
import { LocalBackend } from 'llmtxt/local';
|
|
74
|
-
|
|
75
|
-
const backend = new LocalBackend({ storagePath: './.llmtxt' });
|
|
76
|
-
await backend.open();
|
|
77
|
-
|
|
78
|
-
const doc = await backend.createDocument({ title: 'My Spec', createdBy: 'agent-1' });
|
|
79
|
-
await backend.publishVersion({ documentId: doc.id, content: '# Spec', patchText: '', createdBy: 'agent-1', changelog: 'Initial' });
|
|
80
|
-
await backend.close();
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## RemoteBackend (HTTP/WS Client)
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
import { RemoteBackend } from 'llmtxt/remote';
|
|
87
|
-
|
|
88
|
-
const backend = new RemoteBackend({ baseUrl: 'https://api.llmtxt.my', apiKey: process.env.LLMTXT_API_KEY });
|
|
89
|
-
await backend.open();
|
|
90
|
-
// Same calls as LocalBackend — same Backend interface.
|
|
91
|
-
await backend.close();
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## CLI
|
|
260
|
+
## CLI Reference
|
|
95
261
|
|
|
96
262
|
```bash
|
|
97
|
-
#
|
|
263
|
+
# Core
|
|
98
264
|
llmtxt init
|
|
99
|
-
|
|
100
|
-
# Create a document
|
|
101
265
|
llmtxt create-doc "My Specification"
|
|
102
|
-
|
|
103
|
-
# Push a version from stdin
|
|
104
|
-
cat spec.md | llmtxt push-version my-specification "First draft"
|
|
105
|
-
|
|
106
|
-
# Sync local ↔ remote
|
|
266
|
+
cat spec.md | llmtxt push-version my-spec "First draft"
|
|
107
267
|
llmtxt sync --remote https://api.llmtxt.my --api-key $KEY
|
|
268
|
+
|
|
269
|
+
# Export / Import
|
|
270
|
+
llmtxt export <slug> --format md --output ./specs/
|
|
271
|
+
llmtxt export <slug> --format json --output ./exports/ --sign
|
|
272
|
+
llmtxt export-all --format md --output ./docs/
|
|
273
|
+
llmtxt import ./specs/my-doc.md
|
|
274
|
+
|
|
275
|
+
# Binary blob attachments
|
|
276
|
+
llmtxt attach <slug> ./diagram.png --name diagram.png
|
|
277
|
+
llmtxt blobs <slug>
|
|
278
|
+
llmtxt detach <slug> diagram.png
|
|
279
|
+
|
|
280
|
+
# Agent session lifecycle
|
|
281
|
+
llmtxt session start <agentId>
|
|
282
|
+
llmtxt session end <sessionId>
|
|
283
|
+
|
|
284
|
+
# P2P mesh
|
|
285
|
+
llmtxt mesh start
|
|
286
|
+
llmtxt mesh stop
|
|
287
|
+
llmtxt mesh status
|
|
288
|
+
llmtxt mesh peers
|
|
289
|
+
llmtxt mesh sync
|
|
108
290
|
```
|
|
109
291
|
|
|
110
292
|
## What Ships
|
|
111
293
|
|
|
112
294
|
- Compression, hashing, base62, token estimation (Rust WASM)
|
|
113
|
-
- Signed URL generation and verification
|
|
295
|
+
- Signed URL generation and verification (HMAC-SHA256, Ed25519)
|
|
114
296
|
- Unified diff patch creation, application, version reconstruction
|
|
297
|
+
- Loro CRDT via WASM (crdt_new_doc, crdt_apply_update, crdt_merge_updates, crdt_diff_update)
|
|
115
298
|
- Multi-way diff across up to 5 agent versions (LCS-aligned, WASM)
|
|
116
299
|
- Cherry-pick merge: selectively assemble sections from multiple versions (WASM)
|
|
117
300
|
- Progressive disclosure: overview, section extraction, content search
|
|
118
301
|
- Collaborative document lifecycle (DRAFT, REVIEW, LOCKED, ARCHIVED)
|
|
302
|
+
- AgentSession: open / contribute / close with signed ContributionReceipt
|
|
303
|
+
- Document export (4 formats, deterministic, signed) and import
|
|
304
|
+
- Binary blob attachments (content-addressed SHA-256, hash-verify-on-read)
|
|
305
|
+
- Topology factory: standalone / hub-spoke / mesh via `createBackend()`
|
|
306
|
+
- cr-sqlite changeset sync (optional peer dep `@vlcn.io/crsqlite`)
|
|
307
|
+
- P2P mesh sync engine (Ed25519 mutual handshake, Unix socket + HTTP transports)
|
|
119
308
|
- Version stack management with attribution tracking
|
|
120
309
|
- Consensus/approval evaluation with stale review handling
|
|
121
310
|
- Token-budget-aware retrieval planning
|
|
122
311
|
- Storage content reference abstractions (inline vs object-store)
|
|
123
|
-
- Attachment client helpers for upload, fetch, reshare, versioning
|
|
124
312
|
|
|
125
313
|
## Release Model
|
|
126
314
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* a2a.test.ts — T419: A2A over Mesh tests
|
|
3
|
+
*
|
|
4
|
+
* 5 tests covering:
|
|
5
|
+
* 1. Direct send: signed message delivered to directly-connected peer.
|
|
6
|
+
* 2. SECURITY: unsigned/invalid-sig message is rejected before delivery.
|
|
7
|
+
* 3. Relay path: message forwarded via connected peer when target not direct.
|
|
8
|
+
* 4. Queue: message queued locally when no relay path found.
|
|
9
|
+
* 5. Payload size limit: payload >1 MB is rejected at send.
|
|
10
|
+
*
|
|
11
|
+
* Spec: P3-p2p-mesh.md §7, §10
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=a2a.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/a2a.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* a2a.test.ts — T419: A2A over Mesh tests
|
|
3
|
+
*
|
|
4
|
+
* 5 tests covering:
|
|
5
|
+
* 1. Direct send: signed message delivered to directly-connected peer.
|
|
6
|
+
* 2. SECURITY: unsigned/invalid-sig message is rejected before delivery.
|
|
7
|
+
* 3. Relay path: message forwarded via connected peer when target not direct.
|
|
8
|
+
* 4. Queue: message queued locally when no relay path found.
|
|
9
|
+
* 5. Payload size limit: payload >1 MB is rejected at send.
|
|
10
|
+
*
|
|
11
|
+
* Spec: P3-p2p-mesh.md §7, §10
|
|
12
|
+
*/
|
|
13
|
+
import { describe, it, before } from 'node:test';
|
|
14
|
+
import assert from 'node:assert/strict';
|
|
15
|
+
import { AgentIdentity } from '../identity.js';
|
|
16
|
+
import { MeshMessenger } from '../mesh/a2a.js';
|
|
17
|
+
// ── Helpers ───────────────────────────────────────────────────────
|
|
18
|
+
const MSG_TYPE_A2A = 0x10;
|
|
19
|
+
function buildA2AFrame(envelope) {
|
|
20
|
+
const json = JSON.stringify(envelope);
|
|
21
|
+
const jsonBytes = new TextEncoder().encode(json);
|
|
22
|
+
const out = new Uint8Array(1 + jsonBytes.length);
|
|
23
|
+
out[0] = MSG_TYPE_A2A;
|
|
24
|
+
out.set(jsonBytes, 1);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
function mockTransport(opts) {
|
|
28
|
+
const sent = [];
|
|
29
|
+
let listener;
|
|
30
|
+
return {
|
|
31
|
+
type: 'mock-a2a',
|
|
32
|
+
sent,
|
|
33
|
+
simulateInbound(peerId, data) {
|
|
34
|
+
listener?.(peerId, data);
|
|
35
|
+
},
|
|
36
|
+
async listen(cb) {
|
|
37
|
+
listener = cb;
|
|
38
|
+
},
|
|
39
|
+
async sendChangeset(peerId, _address, data) {
|
|
40
|
+
if (opts?.failForPeer && peerId === opts.failForPeer) {
|
|
41
|
+
throw new Error(`[mock] peer ${peerId} unreachable`);
|
|
42
|
+
}
|
|
43
|
+
sent.push({ peerId, data });
|
|
44
|
+
await opts?.onSend?.(peerId, data);
|
|
45
|
+
},
|
|
46
|
+
async close() {
|
|
47
|
+
// no-op
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function mockDiscovery(peers) {
|
|
52
|
+
return {
|
|
53
|
+
async discover() {
|
|
54
|
+
return peers;
|
|
55
|
+
},
|
|
56
|
+
markInactive(_id) { },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function makeIdentity() {
|
|
60
|
+
const seed = new Uint8Array(32);
|
|
61
|
+
globalThis.crypto.getRandomValues(seed);
|
|
62
|
+
return AgentIdentity.fromSeed(seed);
|
|
63
|
+
}
|
|
64
|
+
// ── Tests ─────────────────────────────────────────────────────────
|
|
65
|
+
describe('MeshMessenger', () => {
|
|
66
|
+
let senderIdentity;
|
|
67
|
+
let recipientIdentity;
|
|
68
|
+
before(async () => {
|
|
69
|
+
senderIdentity = await makeIdentity();
|
|
70
|
+
recipientIdentity = await makeIdentity();
|
|
71
|
+
});
|
|
72
|
+
it('test-1: direct send — signed message delivered to directly-connected peer', async () => {
|
|
73
|
+
const transport = mockTransport();
|
|
74
|
+
const peers = [
|
|
75
|
+
{
|
|
76
|
+
agentId: recipientIdentity.pubkeyHex,
|
|
77
|
+
address: 'unix:/tmp/recv.sock',
|
|
78
|
+
pubkeyBase64: Buffer.from(recipientIdentity.pk).toString('base64'),
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
const discovery = mockDiscovery(peers);
|
|
82
|
+
const received = [];
|
|
83
|
+
const messenger = new MeshMessenger({
|
|
84
|
+
identity: senderIdentity,
|
|
85
|
+
transport,
|
|
86
|
+
discovery,
|
|
87
|
+
onMessage: (env) => received.push(env),
|
|
88
|
+
});
|
|
89
|
+
await messenger.start();
|
|
90
|
+
await messenger.send(recipientIdentity.pubkeyHex, { action: 'ping' });
|
|
91
|
+
await messenger.stop();
|
|
92
|
+
assert.equal(transport.sent.length, 1, 'one send call expected');
|
|
93
|
+
const frame = transport.sent[0];
|
|
94
|
+
assert.equal(frame.peerId, recipientIdentity.pubkeyHex);
|
|
95
|
+
assert.equal(frame.data[0], MSG_TYPE_A2A);
|
|
96
|
+
// Decode envelope.
|
|
97
|
+
const json = new TextDecoder().decode(frame.data.slice(1));
|
|
98
|
+
const env = JSON.parse(json);
|
|
99
|
+
assert.equal(env.type, 'a2a');
|
|
100
|
+
assert.equal(env.from, senderIdentity.pubkeyHex);
|
|
101
|
+
assert.equal(env.to, recipientIdentity.pubkeyHex);
|
|
102
|
+
assert.ok(typeof env.sig === 'string' && env.sig.length > 0, 'message must be signed');
|
|
103
|
+
assert.deepEqual(env.payload, { action: 'ping' });
|
|
104
|
+
});
|
|
105
|
+
it('test-2: SECURITY — unsigned/invalid-sig inbound message is rejected', async () => {
|
|
106
|
+
const transport = mockTransport();
|
|
107
|
+
const discovery = mockDiscovery([]);
|
|
108
|
+
const received = [];
|
|
109
|
+
const rejections = [];
|
|
110
|
+
const messenger = new MeshMessenger({
|
|
111
|
+
identity: recipientIdentity,
|
|
112
|
+
transport,
|
|
113
|
+
discovery,
|
|
114
|
+
onMessage: (env) => received.push(env),
|
|
115
|
+
});
|
|
116
|
+
messenger.on('security-rejection', (r) => rejections.push(r));
|
|
117
|
+
await messenger.start();
|
|
118
|
+
// Build a message with an invalid signature.
|
|
119
|
+
const badEnvelope = {
|
|
120
|
+
type: 'a2a',
|
|
121
|
+
from: senderIdentity.pubkeyHex,
|
|
122
|
+
to: recipientIdentity.pubkeyHex,
|
|
123
|
+
payload: { action: 'malicious' },
|
|
124
|
+
sig: Buffer.from('invalid-sig-bytes-xxxx').toString('base64'),
|
|
125
|
+
sentAt: new Date().toISOString(),
|
|
126
|
+
};
|
|
127
|
+
const frame = buildA2AFrame(badEnvelope);
|
|
128
|
+
transport.simulateInbound('attacker', frame);
|
|
129
|
+
// Allow async verification to complete.
|
|
130
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
131
|
+
await messenger.stop();
|
|
132
|
+
assert.equal(received.length, 0, 'message with invalid sig MUST NOT be delivered');
|
|
133
|
+
assert.ok(rejections.length >= 1, 'security-rejection event must be emitted');
|
|
134
|
+
});
|
|
135
|
+
it('test-3: relay path — message forwarded through connected peer', async () => {
|
|
136
|
+
// senderIdentity → relay agent → recipientIdentity
|
|
137
|
+
const relayAgentId = 'relay-agent-hex-pubkey';
|
|
138
|
+
const transport = mockTransport();
|
|
139
|
+
// Only relay is directly connected; recipient is NOT in peer list.
|
|
140
|
+
const peers = [
|
|
141
|
+
{
|
|
142
|
+
agentId: relayAgentId,
|
|
143
|
+
address: 'unix:/tmp/relay.sock',
|
|
144
|
+
pubkeyBase64: Buffer.alloc(32, 0x44).toString('base64'),
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
const discovery = mockDiscovery(peers);
|
|
148
|
+
const messenger = new MeshMessenger({
|
|
149
|
+
identity: senderIdentity,
|
|
150
|
+
transport,
|
|
151
|
+
discovery,
|
|
152
|
+
});
|
|
153
|
+
await messenger.start();
|
|
154
|
+
// Should relay since recipient not directly connected.
|
|
155
|
+
await messenger.send(recipientIdentity.pubkeyHex, { action: 'routed-task' });
|
|
156
|
+
await messenger.stop();
|
|
157
|
+
// Message should have been sent to relay agent.
|
|
158
|
+
const relaySends = transport.sent.filter((s) => s.peerId === relayAgentId);
|
|
159
|
+
assert.ok(relaySends.length >= 1, 'message must be forwarded to relay peer');
|
|
160
|
+
// Verify the relay frame contains the inner envelope.
|
|
161
|
+
const relayFrame = relaySends[0];
|
|
162
|
+
assert.equal(relayFrame.data[0], MSG_TYPE_A2A);
|
|
163
|
+
const json = new TextDecoder().decode(relayFrame.data.slice(1));
|
|
164
|
+
const parsed = JSON.parse(json);
|
|
165
|
+
// The relay wraps in a relay frame.
|
|
166
|
+
assert.equal(parsed.type, 'relay', 'relay frame type must be "relay"');
|
|
167
|
+
assert.ok(parsed.inner, 'relay frame must contain inner envelope');
|
|
168
|
+
assert.equal(parsed.inner.to, recipientIdentity.pubkeyHex);
|
|
169
|
+
});
|
|
170
|
+
it('test-4: no-path — message queued locally when no relay found', async () => {
|
|
171
|
+
const transport = mockTransport();
|
|
172
|
+
// No peers at all — no direct or relay path.
|
|
173
|
+
const discovery = mockDiscovery([]);
|
|
174
|
+
const queued = [];
|
|
175
|
+
const messenger = new MeshMessenger({
|
|
176
|
+
identity: senderIdentity,
|
|
177
|
+
transport,
|
|
178
|
+
discovery,
|
|
179
|
+
});
|
|
180
|
+
messenger.on('queued', (e) => queued.push(e));
|
|
181
|
+
await messenger.start();
|
|
182
|
+
await messenger.send(recipientIdentity.pubkeyHex, { action: 'offline-task' });
|
|
183
|
+
await messenger.stop();
|
|
184
|
+
assert.equal(transport.sent.length, 0, 'nothing must be sent when no path exists');
|
|
185
|
+
const status = messenger.getQueueStatus();
|
|
186
|
+
const totalQueued = Object.values(status).reduce((a, b) => a + b, 0);
|
|
187
|
+
assert.ok(totalQueued >= 1, 'message must be queued locally');
|
|
188
|
+
assert.ok(queued.length >= 1, 'queued event must be emitted');
|
|
189
|
+
});
|
|
190
|
+
it('test-5: payload >1 MB is rejected at send', async () => {
|
|
191
|
+
const transport = mockTransport();
|
|
192
|
+
const peers = [
|
|
193
|
+
{
|
|
194
|
+
agentId: recipientIdentity.pubkeyHex,
|
|
195
|
+
address: 'unix:/tmp/recv.sock',
|
|
196
|
+
pubkeyBase64: Buffer.from(recipientIdentity.pk).toString('base64'),
|
|
197
|
+
},
|
|
198
|
+
];
|
|
199
|
+
const discovery = mockDiscovery(peers);
|
|
200
|
+
const messenger = new MeshMessenger({
|
|
201
|
+
identity: senderIdentity,
|
|
202
|
+
transport,
|
|
203
|
+
discovery,
|
|
204
|
+
});
|
|
205
|
+
await messenger.start();
|
|
206
|
+
// Build a payload just over 1 MB.
|
|
207
|
+
const bigString = 'x'.repeat(1024 * 1024 + 1);
|
|
208
|
+
await assert.rejects(() => messenger.send(recipientIdentity.pubkeyHex, { data: bigString }), (err) => {
|
|
209
|
+
assert.ok(err instanceof Error, 'must throw an Error');
|
|
210
|
+
assert.ok(err.message.includes('1 MB'), `error message must mention 1 MB limit, got: ${err.message}`);
|
|
211
|
+
return true;
|
|
212
|
+
}, 'send must reject payloads over 1 MB');
|
|
213
|
+
assert.equal(transport.sent.length, 0, 'oversized payload must not be sent');
|
|
214
|
+
await messenger.stop();
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
//# sourceMappingURL=a2a.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a.test.js","sourceRoot":"","sources":["../../src/__tests__/a2a.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAoB,MAAM,gBAAgB,CAAC;AAGjE,qEAAqE;AAErE,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,SAAS,aAAa,CAAC,QAAqB;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACjD,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACtB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,IAGtB;IAIC,MAAM,IAAI,GAAgD,EAAE,CAAC;IAC7D,IAAI,QAAkE,CAAC;IAEvE,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI;QACJ,eAAe,CAAC,MAAc,EAAE,IAAgB;YAC9C,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,EAA8C;YACzD,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAgB;YACpE,IAAI,IAAI,EAAE,WAAW,IAAI,MAAM,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,eAAe,MAAM,cAAc,CAAC,CAAC;YACvD,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5B,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,CAAC,KAAK;YACT,QAAQ;QACV,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,OAAO;QACL,KAAK,CAAC,QAAQ;YACZ,OAAO,KAAK,CAAC;QACf,CAAC;QACD,YAAY,CAAC,GAAW,IAAG,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,YAAY;IACzB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAChC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,qEAAqE;AAErE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAI,cAA6B,CAAC;IAClC,IAAI,iBAAgC,CAAC;IAErC,MAAM,CAAC,KAAK,IAAI,EAAE;QAChB,cAAc,GAAG,MAAM,YAAY,EAAE,CAAC;QACtC,iBAAiB,GAAG,MAAM,YAAY,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,KAAK,GAAe;YACxB;gBACE,OAAO,EAAE,iBAAiB,CAAC,SAAS;gBACpC,OAAO,EAAE,qBAAqB;gBAC9B,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACnE;SACF,CAAC;QACF,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAEvC,MAAM,QAAQ,GAAkB,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC;YAClC,QAAQ,EAAE,cAAc;YACxB,SAAS;YACT,SAAS;YACT,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;SACvC,CAAC,CAAC;QAEH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QACxB,MAAM,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACtE,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QAE1C,mBAAmB;QACnB,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgB,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,CAAC,EAAE,CAAC,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,wBAAwB,CAAC,CAAC;QACvF,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAEpC,MAAM,QAAQ,GAAkB,EAAE,CAAC;QACnC,MAAM,UAAU,GAAc,EAAE,CAAC;QAEjC,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC;YAClC,QAAQ,EAAE,iBAAiB;YAC3B,SAAS;YACT,SAAS;YACT,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;SACvC,CAAC,CAAC;QACH,SAAS,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9D,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QAExB,6CAA6C;QAC7C,MAAM,WAAW,GAAgB;YAC/B,IAAI,EAAE,KAAK;YACX,IAAI,EAAE,cAAc,CAAC,SAAS;YAC9B,EAAE,EAAE,iBAAiB,CAAC,SAAS;YAC/B,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE;YAChC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC7D,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACjC,CAAC;QACF,MAAM,KAAK,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QACzC,SAAS,CAAC,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAE7C,wCAAwC;QACxC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7C,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,gDAAgD,CAAC,CAAC;QACnF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,0CAA0C,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,mDAAmD;QACnD,MAAM,YAAY,GAAG,wBAAwB,CAAC;QAC9C,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,mEAAmE;QACnE,MAAM,KAAK,GAAe;YACxB;gBACE,OAAO,EAAE,YAAY;gBACrB,OAAO,EAAE,sBAAsB;gBAC/B,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACxD;SACF,CAAC;QACF,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAEvC,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC;YAClC,QAAQ,EAAE,cAAc;YACxB,SAAS;YACT,SAAS;SACV,CAAC,CAAC;QAEH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QACxB,uDAAuD;QACvD,MAAM,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QAC7E,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,gDAAgD;QAChD,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;QAC3E,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,yCAAyC,CAAC,CAAC;QAE7E,sDAAsD;QACtD,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA0C,CAAC;QACzE,oCAAoC;QACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,kCAAkC,CAAC,CAAC;QACvE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,yCAAyC,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAM,CAAC,EAAE,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,6CAA6C;QAC7C,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAEpC,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC;YAClC,QAAQ,EAAE,cAAc;YACxB,SAAS;YACT,SAAS;SACV,CAAC,CAAC;QACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9C,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QACxB,MAAM,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9E,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,0CAA0C,CAAC,CAAC;QACnF,MAAM,MAAM,GAAG,SAAS,CAAC,cAAc,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,EAAE,CAAC,WAAW,IAAI,CAAC,EAAE,gCAAgC,CAAC,CAAC;QAC9D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,8BAA8B,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,KAAK,GAAe;YACxB;gBACE,OAAO,EAAE,iBAAiB,CAAC,SAAS;gBACpC,OAAO,EAAE,qBAAqB;gBAC9B,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACnE;SACF,CAAC;QACF,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAEvC,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC;YAClC,QAAQ,EAAE,cAAc;YACxB,SAAS;YACT,SAAS;SACV,CAAC,CAAC;QAEH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QAExB,kCAAkC;QAClC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;QAC9C,MAAM,MAAM,CAAC,OAAO,CAClB,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EACtE,CAAC,GAAU,EAAE,EAAE;YACb,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,EAAE,qBAAqB,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CACP,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC5B,+CAA+C,GAAG,CAAC,OAAO,EAAE,CAC7D,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC,EACD,qCAAqC,CACtC,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,oCAAoC,CAAC,CAAC;QAC7E,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Backend contract test suite.
|
|
2
|
+
* Backend contract test suite — parametrized over LocalBackend and PostgresBackend.
|
|
3
3
|
*
|
|
4
|
-
* Runs the same set of behavioural assertions against any Backend
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* in CI without a running server).
|
|
4
|
+
* Runs the same set of behavioural assertions against any Backend implementation.
|
|
5
|
+
* Each describe block receives a BackendFactory and runs identical assertions
|
|
6
|
+
* regardless of which backend is under test.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Backends:
|
|
9
|
+
* - LocalBackend (SQLite, temp dir) — always runs.
|
|
10
|
+
* - PostgresBackend (Postgres via DATABASE_URL_PG env) — skipped with WARN if
|
|
11
|
+
* DATABASE_URL_PG is not set. Never fails the suite when absent.
|
|
12
|
+
*
|
|
13
|
+
* Output format:
|
|
14
|
+
* [LocalBackend] documents.create …
|
|
15
|
+
* [PostgresBackend] documents.create … (or SKIPPED if no PG)
|
|
16
|
+
*
|
|
17
|
+
* Multi-agent semantic tests (added in T361):
|
|
18
|
+
* - Lease contention: agent-1 acquires, agent-2 blocked, release, agent-2 acquires.
|
|
19
|
+
* - A2A round-trip: send + pollInbox + markRead (deleteA2AMessage).
|
|
20
|
+
* - Scratchpad round-trip: send + poll + delete.
|
|
21
|
+
* - Identity: register + lookup + revoke + nonce replay prevention.
|
|
11
22
|
*/
|
|
12
23
|
export {};
|
|
13
24
|
//# sourceMappingURL=backend-contract.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend-contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/backend-contract.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"backend-contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/backend-contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|