llmtxt 2026.4.7 → 2026.4.9
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 +107 -0
- package/README.md +59 -1
- package/dist/__tests__/a2a.test.js +26 -22
- package/dist/__tests__/a2a.test.js.map +1 -1
- package/dist/__tests__/events-contract.test.d.ts +13 -0
- package/dist/__tests__/events-contract.test.d.ts.map +1 -0
- package/dist/__tests__/events-contract.test.js +167 -0
- package/dist/__tests__/events-contract.test.js.map +1 -0
- package/dist/__tests__/identity.contract.test.d.ts +15 -0
- package/dist/__tests__/identity.contract.test.d.ts.map +1 -0
- package/dist/__tests__/identity.contract.test.js +242 -0
- package/dist/__tests__/identity.contract.test.js.map +1 -0
- package/dist/__tests__/mesh-5-peer.test.js +1 -1
- package/dist/__tests__/mesh-5-peer.test.js.map +1 -1
- package/dist/__tests__/presence.test.js +18 -21
- package/dist/__tests__/presence.test.js.map +1 -1
- package/dist/__tests__/security-primitives.test.d.ts +15 -0
- package/dist/__tests__/security-primitives.test.d.ts.map +1 -0
- package/dist/__tests__/security-primitives.test.js +88 -0
- package/dist/__tests__/security-primitives.test.js.map +1 -0
- package/dist/__tests__/sync-engine.test.js +22 -21
- package/dist/__tests__/sync-engine.test.js.map +1 -1
- package/dist/__tests__/transport-contract.test.d.ts +20 -0
- package/dist/__tests__/transport-contract.test.d.ts.map +1 -0
- package/dist/__tests__/transport-contract.test.js +205 -0
- package/dist/__tests__/transport-contract.test.js.map +1 -0
- package/dist/__tests__/transport.test.js +1 -1
- package/dist/__tests__/transport.test.js.map +1 -1
- package/dist/backend/factory.d.ts +2 -2
- package/dist/backend/factory.d.ts.map +1 -1
- package/dist/backend/factory.js +7 -2
- package/dist/backend/factory.js.map +1 -1
- package/dist/blob/__tests__/contract.test.d.ts +21 -0
- package/dist/blob/__tests__/contract.test.d.ts.map +1 -0
- package/dist/blob/__tests__/contract.test.js +335 -0
- package/dist/blob/__tests__/contract.test.js.map +1 -0
- package/dist/blob/changeset.d.ts +105 -0
- package/dist/blob/changeset.d.ts.map +1 -0
- package/dist/blob/changeset.js +169 -0
- package/dist/blob/changeset.js.map +1 -0
- package/dist/blob/fs-adapter.d.ts +86 -0
- package/dist/blob/fs-adapter.d.ts.map +1 -0
- package/dist/blob/fs-adapter.js +293 -0
- package/dist/blob/fs-adapter.js.map +1 -0
- package/dist/blob/index.d.ts +49 -0
- package/dist/blob/index.d.ts.map +1 -0
- package/dist/blob/index.js +51 -0
- package/dist/blob/index.js.map +1 -0
- package/dist/blob/primitives.d.ts +26 -0
- package/dist/blob/primitives.d.ts.map +1 -0
- package/dist/blob/primitives.js +36 -0
- package/dist/blob/primitives.js.map +1 -0
- package/dist/cli/llmtxt.js +2 -2
- package/dist/cli/llmtxt.js.map +1 -1
- package/dist/crdt/crdt.contract.test.d.ts +24 -0
- package/dist/crdt/crdt.contract.test.d.ts.map +1 -0
- package/dist/crdt/crdt.contract.test.js +130 -0
- package/dist/crdt/crdt.contract.test.js.map +1 -0
- package/dist/events/bus.d.ts +81 -0
- package/dist/events/bus.d.ts.map +1 -0
- package/dist/events/bus.js +139 -0
- package/dist/events/bus.js.map +1 -0
- package/dist/events/index.d.ts +40 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +36 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/stream.d.ts +29 -0
- package/dist/events/stream.d.ts.map +1 -0
- package/dist/events/stream.js +72 -0
- package/dist/events/stream.js.map +1 -0
- package/dist/events/types.d.ts +43 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +8 -0
- package/dist/events/types.js.map +1 -0
- package/dist/identity/agent-identity.d.ts +165 -0
- package/dist/identity/agent-identity.d.ts.map +1 -0
- package/dist/identity/agent-identity.js +309 -0
- package/dist/identity/agent-identity.js.map +1 -0
- package/dist/identity/index.d.ts +55 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +54 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity.d.ts +7 -98
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +8 -239
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/local/blob-changeset.d.ts +7 -99
- package/dist/local/blob-changeset.d.ts.map +1 -1
- package/dist/local/blob-changeset.js +6 -162
- package/dist/local/blob-changeset.js.map +1 -1
- package/dist/local/blob-fs-adapter.d.ts +6 -79
- package/dist/local/blob-fs-adapter.d.ts.map +1 -1
- package/dist/local/blob-fs-adapter.js +6 -286
- package/dist/local/blob-fs-adapter.js.map +1 -1
- package/dist/mesh/sync-engine.d.ts +2 -10
- package/dist/mesh/sync-engine.d.ts.map +1 -1
- package/dist/mesh/sync-engine.js.map +1 -1
- package/dist/sanitize.d.ts +93 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +193 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/sdk/sdk.contract.test.d.ts +17 -0
- package/dist/sdk/sdk.contract.test.d.ts.map +1 -0
- package/dist/sdk/sdk.contract.test.js +381 -0
- package/dist/sdk/sdk.contract.test.js.map +1 -0
- package/dist/similarity/similarity.contract.test.d.ts +25 -0
- package/dist/similarity/similarity.contract.test.d.ts.map +1 -0
- package/dist/similarity/similarity.contract.test.js +267 -0
- package/dist/similarity/similarity.contract.test.js.map +1 -0
- package/dist/{mesh/transport.d.ts → transport/index.d.ts} +7 -4
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/{mesh/transport.js → transport/index.js} +7 -4
- package/dist/transport/index.js.map +1 -0
- package/dist/wasm.d.ts +41 -0
- package/dist/wasm.d.ts.map +1 -1
- package/dist/wasm.js +48 -0
- package/dist/wasm.js.map +1 -1
- package/package.json +14 -2
- package/wasm/llmtxt_core.d.ts +92 -0
- package/wasm/llmtxt_core.js +228 -0
- package/wasm/llmtxt_core_bg.wasm +0 -0
- package/wasm/llmtxt_core_bg.wasm.d.ts +52 -44
- package/wasm/package.json +1 -1
- package/dist/mesh/transport.d.ts.map +0 -1
- package/dist/mesh/transport.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,113 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2026.4.9] — 2026-04-18
|
|
11
|
+
|
|
12
|
+
### Added — Shared Primitives Subpath Contract (T550 tree)
|
|
13
|
+
|
|
14
|
+
Seven subpaths are now exported under a formal, versioned stability contract
|
|
15
|
+
(`STABILITY.md`). Breaking changes to any subpath surface trigger a minor bump.
|
|
16
|
+
All subpaths are tree-shakeable and covered by a dedicated contract test suite.
|
|
17
|
+
|
|
18
|
+
| Subpath | Provides |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `llmtxt/blob` | `hashBlob`, `blobNameValidate`, `FilesystemBlobStore`, P2P changeset helpers |
|
|
21
|
+
| `llmtxt/crdt` | `crdtNewDoc`, `crdtApplyUpdate`, `crdtMergeUpdates`, `crdtStateVector`, `crdtDiffUpdate` (Loro WASM) |
|
|
22
|
+
| `llmtxt/events` | `EventBus`, `createEventBus`, typed event helpers for document + CRDT streams |
|
|
23
|
+
| `llmtxt/identity` | `AgentIdentity`, `signRequest`, `verifyRequestSignature`, `canonicalPayload` |
|
|
24
|
+
| `llmtxt/sdk` | `AgentSession`, `DocumentLifecycle`, `VersionStack`, `ConsensusEvaluator`, `RetrievalPlanner`, A2A routing |
|
|
25
|
+
| `llmtxt/similarity` | `textSimilarity`, `rankBySimilarity`, `minhashFingerprint`, `wordShingles` (Rust WASM) |
|
|
26
|
+
| `llmtxt/transport` | `UnixSocketTransport`, `HttpTransport`, `PeerTransport`, Ed25519 mutual handshake |
|
|
27
|
+
|
|
28
|
+
- Contract test suite: `packages/llmtxt/src/__tests__/subpath-contract.test.ts` — validates every export exists and is the expected type.
|
|
29
|
+
- CI guard: `scripts/check-subpath-exports.sh` — fails PR if any contracted export is removed without a version bump.
|
|
30
|
+
- `STABILITY.md` added to `packages/llmtxt/` documenting stability guarantees and deprecation policy.
|
|
31
|
+
|
|
32
|
+
### Added — Demo Harness 8/8 (T380/T381/T382)
|
|
33
|
+
|
|
34
|
+
- All 8 demo scenarios (progressive disclosure, agent collaboration, conflict resolution, BFT consensus, export/import, blob attachments, mesh sync, session lifecycle) now complete without errors.
|
|
35
|
+
- Demo harness integrated into CI; failures block release.
|
|
36
|
+
|
|
37
|
+
### Added — P0 Security Remediation (T108 — 10 items)
|
|
38
|
+
|
|
39
|
+
- CSP `Content-Security-Policy` + HSTS + `Cross-Origin-Embedder-Policy` / `Cross-Origin-Opener-Policy` headers on all routes (T162/T163).
|
|
40
|
+
- XSS sanitization via DOMPurify on all user-controlled display paths.
|
|
41
|
+
- Webhook delivery hardening: DLQ with exponential backoff, max-retry cap, dead-letter audit log (T165).
|
|
42
|
+
- PostgreSQL Row-Level Security (RLS) enabled on 21 tenant-scoped tables; no cross-tenant data leakage in any RLS-covered query (T166).
|
|
43
|
+
- Anonymous mode threat model: aggressive rate limits (10 req/min per IP), abuse fingerprinting, and explicit capability matrix (T167).
|
|
44
|
+
|
|
45
|
+
### Added — Tamper-Evident Audit Log (T164/T107)
|
|
46
|
+
|
|
47
|
+
- Merkle chain appended to every audit-log entry; root hash published to append-only `audit_roots` table.
|
|
48
|
+
- RFC 3161 timestamp token requested for each root hash; token stored alongside entry for offline verification.
|
|
49
|
+
- `GET /audit/:id/verify` returns Merkle proof + TSA token for any entry.
|
|
50
|
+
|
|
51
|
+
### Added — Graceful Shutdown (T092)
|
|
52
|
+
|
|
53
|
+
- `SIGTERM` handler drains in-flight requests (max 30 s), flushes event log, closes DB pool, emits `server.shutdown` event before exit.
|
|
54
|
+
- Health check at `GET /health` reports `{"status":"draining"}` during shutdown window.
|
|
55
|
+
|
|
56
|
+
### Added — Strict Release Runbook (T158)
|
|
57
|
+
|
|
58
|
+
- `docs/RELEASE-RUNBOOK.md`: gate-by-gate checklist (migrations verified, CI green, npm dry-run, crates.io dry-run, changelog entry, git tag, publish).
|
|
59
|
+
- CI enforces CHANGELOG entry presence before any publish step.
|
|
60
|
+
|
|
61
|
+
### Added — OpenAPI 3.1 (T169)
|
|
62
|
+
|
|
63
|
+
- `GET /docs/api` serves interactive Swagger UI backed by `openapi.json` generated at build time via `forge-ts`.
|
|
64
|
+
- Schema validated against OAS 3.1 spec on every CI run; schema drift fails the build.
|
|
65
|
+
|
|
66
|
+
### Added — SLO/SLI + Burn-Rate Alerts (T157)
|
|
67
|
+
|
|
68
|
+
- P50/P95/P99 latency SLOs defined for all API surface.
|
|
69
|
+
- Grafana alert rules: error-budget burn-rate alert (1 h + 6 h windows) pages on-call when burn rate exceeds 14×.
|
|
70
|
+
- SLO dashboard published at `docs/dashboards/slo.json`.
|
|
71
|
+
|
|
72
|
+
### Added — LLM-First Content Delivery (T014)
|
|
73
|
+
|
|
74
|
+
- SSR content negotiation: requests with `Accept: text/plain` or `Accept: text/markdown` receive raw document bodies without HTML wrapper.
|
|
75
|
+
- `llmtxt` envelope format available at `Accept: application/vnd.llmtxt+json`.
|
|
76
|
+
|
|
77
|
+
### Added — Frontend UX Polish + DiffViewer Rewrite (T030/T031)
|
|
78
|
+
|
|
79
|
+
- DiffViewer component rewritten with syntax-highlighted unified diff, side-by-side toggle, and section-level jump links.
|
|
80
|
+
- Version selector, token-budget labels, and multi-diff mode promoted to stable UI (previously behind feature flag).
|
|
81
|
+
|
|
82
|
+
### Added — Ed25519 Key Rotation + KMS Abstraction (T086/T090)
|
|
83
|
+
|
|
84
|
+
- `POST /keys/rotate` initiates a graceful key rotation: new key published, old key kept for verification for 7 days, then revoked.
|
|
85
|
+
- KMS abstraction layer: `LocalKms` (file-based, dev/test) + `AwsKmsAdapter` (production). Swap via `KMS_PROVIDER` env var.
|
|
86
|
+
|
|
87
|
+
### Added — GDPR Compliance Suite (T094/T168/T186/T187)
|
|
88
|
+
|
|
89
|
+
- `GET /me/export` generates a signed ZIP archive of all user data (documents, versions, events, audit log entries).
|
|
90
|
+
- `DELETE /me` triggers right-to-erasure: pseudonymizes all PII fields within 30 s, queues blob deletion, emits `gdpr.erasure` event.
|
|
91
|
+
- Retention policy: configurable `DATA_RETENTION_DAYS`; cron job purges expired rows and blobs nightly.
|
|
92
|
+
- Erasure log: every erasure request appended to `gdpr_erasure_log` table for DPA audit trail.
|
|
93
|
+
|
|
94
|
+
### Added — SOC 2 Type 1 Readiness (T184/T185/T188)
|
|
95
|
+
|
|
96
|
+
- Sub-processor list published at `docs/legal/sub-processors.md`.
|
|
97
|
+
- Data Processing Agreement (DPA) template at `docs/legal/dpa-template.md`.
|
|
98
|
+
- Data residency controls: `DATA_RESIDENCY_REGION` env var routes Postgres connections and S3 bucket writes to a named region.
|
|
99
|
+
- `docs/compliance/soc2-readiness.md` documents control mapping against TSC CC6–CC9.
|
|
100
|
+
|
|
101
|
+
### Added — Monetization Foundation (T009/T010/T011)
|
|
102
|
+
|
|
103
|
+
- Usage tracking: every API call increments a per-tenant `api_calls` counter; daily roll-up to `usage_daily` table.
|
|
104
|
+
- Tier management: `free` (1 000 req/day, 10 MB blob), `pro` (100 000 req/day, 10 GB blob), `enterprise` (unlimited, custom).
|
|
105
|
+
- Stripe integration: `POST /billing/checkout` creates a Stripe Checkout session; webhook at `POST /billing/webhook` handles subscription events and writes tier to `tenants.tier`.
|
|
106
|
+
- Pro tier gate middleware: returns `402 Payment Required` with upgrade URL when free-tier limit exceeded.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- `pnpm biome ci .` clean — no lint errors introduced by this release.
|
|
111
|
+
|
|
112
|
+
## [2026.4.8] — 2026-04-17
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
- **Regression from v2026.4.7**: `import('llmtxt')` failed at load time with `ERR_MODULE_NOT_FOUND: Cannot find package 'better-sqlite3'` for consumers that only wanted utility functions (e.g. CLEO's `cleo docs generate` calling `generateOverview`). Root cause: `packages/llmtxt/src/backend/factory.ts` had top-level static `import { LocalBackend }` whose module graph pulled better-sqlite3 into the load-time resolution chain even when `createBackend` was never called. Fix: type-only imports at top of file + runtime `await import(...)` inside the matching createBackend branch. Module resolution now only happens when the consumer instantiates the specific topology that needs it.
|
|
116
|
+
|
|
10
117
|
## [2026.4.7] — 2026-04-17
|
|
11
118
|
|
|
12
119
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# llmtxt
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/llmtxt)
|
|
4
4
|
|
|
5
5
|
Primitives and SDK for LLM agent content workflows.
|
|
6
6
|
|
|
7
7
|
`llmtxt` wraps the Rust `llmtxt-core` crate through WASM so TypeScript
|
|
8
8
|
consumers use the same single-source-of-truth logic as native Rust consumers.
|
|
9
9
|
|
|
10
|
+
**v2026.4.9**: Shared Primitives Subpath Contract — 7 stable subpaths (`/sdk`, `/crdt`, `/blob`, `/events`, `/identity`, `/transport`, `/similarity`) with contract tests, STABILITY.md, and a CI guard. Also ships: demo harness 8/8, P0 security remediation (10 items), tamper-evident audit log with Merkle chain + RFC 3161, strict release runbook, OpenAPI 3.1, SLO/SLI alerts, CSP/HSTS/COEP, webhook DLQ, PostgreSQL RLS on 21 tenant tables, Ed25519 key rotation + KMS abstraction, anonymous mode threat model, GDPR export/retention/erasure, SOC 2 Type 1 readiness, and monetization foundation (Stripe + Pro tier).
|
|
11
|
+
|
|
12
|
+
**v2026.4.8** (patch): fixes `import('llmtxt')` triggering `better-sqlite3` / `drizzle-orm` resolution at load time for lightweight consumers (e.g. `generateOverview`).
|
|
13
|
+
|
|
10
14
|
**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
15
|
|
|
12
16
|
**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.
|
|
@@ -245,6 +249,25 @@ const merged = cherryPickMerge(
|
|
|
245
249
|
);
|
|
246
250
|
```
|
|
247
251
|
|
|
252
|
+
## Shared Primitives (v2026.4.9 Subpath Contract)
|
|
253
|
+
|
|
254
|
+
Seven stable subpaths are now exported under a formal contract with semver-guarded
|
|
255
|
+
stability guarantees documented in `STABILITY.md`. All subpaths are tree-shakeable
|
|
256
|
+
and independently importable.
|
|
257
|
+
|
|
258
|
+
| Subpath | Description | Import example |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| `llmtxt/blob` | Content-addressed binary blob operations — hash, name-validate, filesystem adapter, P2P changeset | `import { hashBlob, blobNameValidate } from 'llmtxt/blob'` |
|
|
261
|
+
| `llmtxt/crdt` | Real-time collaborative editing via Loro CRDT — section subscriptions, state vector exchange, merge | `import { crdtNewDoc, crdtApplyUpdate } from 'llmtxt/crdt'` |
|
|
262
|
+
| `llmtxt/events` | Document event bus — subscribe, publish, filter, drain; shared by LocalBackend and PostgresBackend | `import { EventBus, createEventBus } from 'llmtxt/events'` |
|
|
263
|
+
| `llmtxt/identity` | Ed25519 agent identity — key generation, request signing, signature verification, canonical payload | `import { AgentIdentity, signRequest } from 'llmtxt/identity'` |
|
|
264
|
+
| `llmtxt/sdk` | Collaborative document SDK — lifecycle, versions, attribution, consensus, AgentSession, A2A, retrieval | `import { AgentSession, DocumentLifecycle } from 'llmtxt/sdk'` |
|
|
265
|
+
| `llmtxt/similarity` | Text similarity — n-gram Jaccard, MinHash fingerprinting, word shingles, ranked search (Rust WASM) | `import { textSimilarity, rankBySimilarity } from 'llmtxt/similarity'` |
|
|
266
|
+
| `llmtxt/transport` | PeerTransport abstraction — UnixSocketTransport, HttpTransport, Ed25519 mutual handshake | `import { UnixSocketTransport, HttpTransport } from 'llmtxt/transport'` |
|
|
267
|
+
|
|
268
|
+
> All 7 subpaths are covered by the contract test suite in `packages/llmtxt/src/__tests__/subpath-contract.test.ts`.
|
|
269
|
+
> Breaking changes to any of these exports increment the minor version per T550 STABILITY.md.
|
|
270
|
+
|
|
248
271
|
## Subpath Exports
|
|
249
272
|
|
|
250
273
|
```ts
|
|
@@ -289,10 +312,45 @@ llmtxt mesh peers
|
|
|
289
312
|
llmtxt mesh sync
|
|
290
313
|
```
|
|
291
314
|
|
|
315
|
+
## Security Helpers
|
|
316
|
+
|
|
317
|
+
### `verifyContentHash(content, expectedHash)` — MITM defense (T-02)
|
|
318
|
+
|
|
319
|
+
Verify that downloaded content matches the `content_hash` field returned by the API.
|
|
320
|
+
Computes `sha256(content)` in Rust (via WASM) and compares it in constant time.
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { verifyContentHash } from 'llmtxt';
|
|
324
|
+
|
|
325
|
+
const content = await fetchDocumentContent(slug);
|
|
326
|
+
const { content_hash } = await fetchDocumentMeta(slug);
|
|
327
|
+
|
|
328
|
+
if (!verifyContentHash(content, content_hash)) {
|
|
329
|
+
throw new Error('Content hash mismatch — possible tampering detected');
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### `constantTimeEqHex(a, b)` — timing-safe digest comparison (S-01)
|
|
334
|
+
|
|
335
|
+
Compare two hex-encoded SHA-256 or HMAC digests without leaking timing information.
|
|
336
|
+
Delegates to `crates/llmtxt-core::crypto::constant_time_eq_hex` (the `subtle` crate).
|
|
337
|
+
Use this instead of JavaScript `===` whenever comparing any secret-derived value.
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import { constantTimeEqHex } from 'llmtxt';
|
|
341
|
+
|
|
342
|
+
// Never: if (storedHash === incomingHash)
|
|
343
|
+
// Always:
|
|
344
|
+
if (constantTimeEqHex(storedHash, incomingHash)) {
|
|
345
|
+
// hashes match — timing-safe
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
292
349
|
## What Ships
|
|
293
350
|
|
|
294
351
|
- Compression, hashing, base62, token estimation (Rust WASM)
|
|
295
352
|
- Signed URL generation and verification (HMAC-SHA256, Ed25519)
|
|
353
|
+
- `verifyContentHash` + `constantTimeEqHex`: timing-safe content integrity helpers
|
|
296
354
|
- Unified diff patch creation, application, version reconstruction
|
|
297
355
|
- Loro CRDT via WASM (crdt_new_doc, crdt_apply_update, crdt_merge_updates, crdt_diff_update)
|
|
298
356
|
- Multi-way diff across up to 5 agent versions (LCS-aligned, WASM)
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { describe, it, before } from 'node:test';
|
|
14
14
|
import assert from 'node:assert/strict';
|
|
15
|
+
import { EventEmitter } from 'node:events';
|
|
15
16
|
import { AgentIdentity } from '../identity.js';
|
|
16
17
|
import { MeshMessenger } from '../mesh/a2a.js';
|
|
17
18
|
// ── Helpers ───────────────────────────────────────────────────────
|
|
@@ -24,29 +25,32 @@ function buildA2AFrame(envelope) {
|
|
|
24
25
|
out.set(jsonBytes, 1);
|
|
25
26
|
return out;
|
|
26
27
|
}
|
|
28
|
+
class MockA2ATransport extends EventEmitter {
|
|
29
|
+
opts;
|
|
30
|
+
type = 'mock-a2a';
|
|
31
|
+
sent = [];
|
|
32
|
+
listener;
|
|
33
|
+
constructor(opts) {
|
|
34
|
+
super();
|
|
35
|
+
this.opts = opts;
|
|
36
|
+
}
|
|
37
|
+
simulateInbound(peerId, data) {
|
|
38
|
+
this.listener?.(peerId, data);
|
|
39
|
+
}
|
|
40
|
+
async listen(cb) {
|
|
41
|
+
this.listener = cb;
|
|
42
|
+
}
|
|
43
|
+
async sendChangeset(peerId, _address, data) {
|
|
44
|
+
if (this.opts?.failForPeer && peerId === this.opts.failForPeer) {
|
|
45
|
+
throw new Error(`[mock] peer ${peerId} unreachable`);
|
|
46
|
+
}
|
|
47
|
+
this.sent.push({ peerId, data });
|
|
48
|
+
await this.opts?.onSend?.(peerId, data);
|
|
49
|
+
}
|
|
50
|
+
async close() { }
|
|
51
|
+
}
|
|
27
52
|
function mockTransport(opts) {
|
|
28
|
-
|
|
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
|
-
};
|
|
53
|
+
return new MockA2ATransport(opts);
|
|
50
54
|
}
|
|
51
55
|
function mockDiscovery(peers) {
|
|
52
56
|
return {
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"a2a.test.js","sourceRoot":"","sources":["../../src/__tests__/a2a.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for llmtxt/events subpath.
|
|
3
|
+
*
|
|
4
|
+
* Verifies:
|
|
5
|
+
* 1. EventBus publisher/subscriber round-trip
|
|
6
|
+
* 2. Ordered delivery (FIFO)
|
|
7
|
+
* 3. Channel isolation (no cross-channel leakage)
|
|
8
|
+
* 4. Subscription cleanup on return()
|
|
9
|
+
* 5. makeEventStream directly
|
|
10
|
+
* 6. Multiple concurrent subscribers
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=events-contract.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/events-contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for llmtxt/events subpath.
|
|
3
|
+
*
|
|
4
|
+
* Verifies:
|
|
5
|
+
* 1. EventBus publisher/subscriber round-trip
|
|
6
|
+
* 2. Ordered delivery (FIFO)
|
|
7
|
+
* 3. Channel isolation (no cross-channel leakage)
|
|
8
|
+
* 4. Subscription cleanup on return()
|
|
9
|
+
* 5. makeEventStream directly
|
|
10
|
+
* 6. Multiple concurrent subscribers
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it } from 'node:test';
|
|
13
|
+
import assert from 'node:assert/strict';
|
|
14
|
+
import { EventEmitter } from 'node:events';
|
|
15
|
+
import { EventBus, makeEventStream } from '../events/index.js';
|
|
16
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
17
|
+
function makeDocumentEvent(overrides) {
|
|
18
|
+
return {
|
|
19
|
+
id: 'evt-1',
|
|
20
|
+
documentId: 'doc-1',
|
|
21
|
+
type: 'version.created',
|
|
22
|
+
agentId: 'agent-1',
|
|
23
|
+
payload: {},
|
|
24
|
+
createdAt: Date.now(),
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function makeCrdtUpdate(overrides) {
|
|
29
|
+
return {
|
|
30
|
+
documentId: 'doc-1',
|
|
31
|
+
sectionKey: 'intro',
|
|
32
|
+
updateBase64: 'AAAA',
|
|
33
|
+
agentId: 'agent-1',
|
|
34
|
+
createdAt: Date.now(),
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Collect `n` items from an async iterable with a timeout. */
|
|
39
|
+
async function collect(iterable, n, timeoutMs = 1000) {
|
|
40
|
+
const results = [];
|
|
41
|
+
const iter = iterable[Symbol.asyncIterator]();
|
|
42
|
+
for (let i = 0; i < n; i++) {
|
|
43
|
+
const p = iter.next();
|
|
44
|
+
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`collect timeout after ${timeoutMs}ms`)), timeoutMs));
|
|
45
|
+
const result = await Promise.race([p, timeout]);
|
|
46
|
+
results.push(result.value);
|
|
47
|
+
}
|
|
48
|
+
await iter.return?.();
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
52
|
+
describe('EventBus', () => {
|
|
53
|
+
it('delivers a single event to a subscriber (round-trip)', async () => {
|
|
54
|
+
const bus = new EventBus();
|
|
55
|
+
const event = makeDocumentEvent();
|
|
56
|
+
const stream = bus.subscribeTyped('events:doc-1');
|
|
57
|
+
const pCollect = collect(stream, 1);
|
|
58
|
+
bus.publishTyped('events:doc-1', event);
|
|
59
|
+
const [received] = await pCollect;
|
|
60
|
+
assert.deepEqual(received, event);
|
|
61
|
+
});
|
|
62
|
+
it('delivers events in FIFO order', async () => {
|
|
63
|
+
const bus = new EventBus();
|
|
64
|
+
const events = [
|
|
65
|
+
makeDocumentEvent({ id: '1', createdAt: 1000 }),
|
|
66
|
+
makeDocumentEvent({ id: '2', createdAt: 2000 }),
|
|
67
|
+
makeDocumentEvent({ id: '3', createdAt: 3000 }),
|
|
68
|
+
];
|
|
69
|
+
const stream = bus.subscribeTyped('events:doc-1');
|
|
70
|
+
const pCollect = collect(stream, 3);
|
|
71
|
+
for (const e of events)
|
|
72
|
+
bus.publishTyped('events:doc-1', e);
|
|
73
|
+
const received = await pCollect;
|
|
74
|
+
assert.deepEqual(received.map((e) => e.id), ['1', '2', '3'], 'events must arrive in publish order');
|
|
75
|
+
});
|
|
76
|
+
it('isolates channels — subscriber on channel A does not receive channel B events', async () => {
|
|
77
|
+
const bus = new EventBus();
|
|
78
|
+
const evtA = makeDocumentEvent({ id: 'A', documentId: 'doc-A' });
|
|
79
|
+
const evtB = makeDocumentEvent({ id: 'B', documentId: 'doc-B' });
|
|
80
|
+
const streamA = bus.subscribeTyped('events:doc-A');
|
|
81
|
+
const pCollect = collect(streamA, 1);
|
|
82
|
+
// Publish to both channels
|
|
83
|
+
bus.publishTyped('events:doc-B', evtB);
|
|
84
|
+
bus.publishTyped('events:doc-A', evtA);
|
|
85
|
+
const [received] = await pCollect;
|
|
86
|
+
assert.equal(received.id, 'A', 'only channel-A event must arrive');
|
|
87
|
+
});
|
|
88
|
+
it('multiple subscribers on the same channel all receive the event', async () => {
|
|
89
|
+
const bus = new EventBus();
|
|
90
|
+
const event = makeDocumentEvent();
|
|
91
|
+
const stream1 = bus.subscribeTyped('events:doc-1');
|
|
92
|
+
const stream2 = bus.subscribeTyped('events:doc-1');
|
|
93
|
+
const p1 = collect(stream1, 1);
|
|
94
|
+
const p2 = collect(stream2, 1);
|
|
95
|
+
bus.publishTyped('events:doc-1', event);
|
|
96
|
+
const [r1] = await p1;
|
|
97
|
+
const [r2] = await p2;
|
|
98
|
+
assert.deepEqual(r1, event);
|
|
99
|
+
assert.deepEqual(r2, event);
|
|
100
|
+
});
|
|
101
|
+
it('unsubscribes cleanly on return() — no events after close', async () => {
|
|
102
|
+
const bus = new EventBus();
|
|
103
|
+
const iter = bus.subscribeTyped('events:doc-1')[Symbol.asyncIterator]();
|
|
104
|
+
// Close the iterator before any events
|
|
105
|
+
await iter.return?.();
|
|
106
|
+
// Verify the emitter has no listeners left on this channel
|
|
107
|
+
assert.equal(bus.emitter.listenerCount('events:doc-1'), 0, 'listener must be removed after return()');
|
|
108
|
+
});
|
|
109
|
+
it('handles CRDT update round-trip', async () => {
|
|
110
|
+
const bus = new EventBus();
|
|
111
|
+
const update = makeCrdtUpdate();
|
|
112
|
+
const stream = bus.subscribeTyped('crdt:doc-1:intro');
|
|
113
|
+
const pCollect = collect(stream, 1);
|
|
114
|
+
bus.publishTyped('crdt:doc-1:intro', update);
|
|
115
|
+
const [received] = await pCollect;
|
|
116
|
+
assert.deepEqual(received, update);
|
|
117
|
+
});
|
|
118
|
+
it('buffers events published before the consumer calls next()', async () => {
|
|
119
|
+
const bus = new EventBus();
|
|
120
|
+
const events = [
|
|
121
|
+
makeDocumentEvent({ id: '1' }),
|
|
122
|
+
makeDocumentEvent({ id: '2' }),
|
|
123
|
+
];
|
|
124
|
+
const stream = bus.subscribeTyped('events:doc-1');
|
|
125
|
+
// Open the iterator FIRST so the listener is registered, then publish
|
|
126
|
+
// before the consumer has called next().
|
|
127
|
+
const iter = stream[Symbol.asyncIterator]();
|
|
128
|
+
// Publish while no one is awaiting next() — events go into the queue
|
|
129
|
+
for (const e of events)
|
|
130
|
+
bus.publishTyped('events:doc-1', e);
|
|
131
|
+
// Now drain — queued items must arrive in order
|
|
132
|
+
const r1 = await iter.next();
|
|
133
|
+
const r2 = await iter.next();
|
|
134
|
+
await iter.return?.();
|
|
135
|
+
assert.deepEqual([r1.value.id, r2.value.id], ['1', '2'], 'buffered events must be delivered in order');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('makeEventStream', () => {
|
|
139
|
+
it('wraps a raw EventEmitter into an AsyncIterable', async () => {
|
|
140
|
+
const emitter = new EventEmitter();
|
|
141
|
+
const event = makeDocumentEvent();
|
|
142
|
+
const stream = makeEventStream(emitter, 'test:channel');
|
|
143
|
+
const pCollect = collect(stream, 1);
|
|
144
|
+
emitter.emit('test:channel', event);
|
|
145
|
+
const [received] = await pCollect;
|
|
146
|
+
assert.deepEqual(received, event);
|
|
147
|
+
});
|
|
148
|
+
it('removes listener from emitter when iterator is returned', async () => {
|
|
149
|
+
const emitter = new EventEmitter();
|
|
150
|
+
const stream = makeEventStream(emitter, 'test:channel');
|
|
151
|
+
const iter = stream[Symbol.asyncIterator]();
|
|
152
|
+
assert.equal(emitter.listenerCount('test:channel'), 1);
|
|
153
|
+
await iter.return?.();
|
|
154
|
+
assert.equal(emitter.listenerCount('test:channel'), 0, 'listener must be removed after return()');
|
|
155
|
+
});
|
|
156
|
+
it('ordered delivery with multiple events', async () => {
|
|
157
|
+
const emitter = new EventEmitter();
|
|
158
|
+
const events = [1, 2, 3, 4, 5].map((n) => makeDocumentEvent({ id: String(n), createdAt: n }));
|
|
159
|
+
const stream = makeEventStream(emitter, 'ordered');
|
|
160
|
+
const pCollect = collect(stream, 5);
|
|
161
|
+
for (const e of events)
|
|
162
|
+
emitter.emit('ordered', e);
|
|
163
|
+
const received = await pCollect;
|
|
164
|
+
assert.deepEqual(received.map((e) => e.id), ['1', '2', '3', '4', '5']);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=events-contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-contract.test.js","sourceRoot":"","sources":["../../src/__tests__/events-contract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for `llmtxt/identity` subpath (T652).
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* 1. Round-trip: createIdentity / identityFromSeed → sign → verify
|
|
6
|
+
* 2. Canonical payload format (method+path+ts+nonce+bodyhash, newline-separated)
|
|
7
|
+
* 3. Signature replay detection shape (nonce uniqueness logic contract)
|
|
8
|
+
* 4. signRequest / verifySignature convenience functions
|
|
9
|
+
* 5. buildCanonicalPayload determinism and field ordering
|
|
10
|
+
* 6. bodyHashHex matches known SHA-256 vectors
|
|
11
|
+
* 7. Cross-verify: SDK sign ↔ SDK verify (same canonical format as Rust)
|
|
12
|
+
* 8. Wrong-key and tamper-detection failures
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=identity.contract.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/identity.contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|