llmtxt 2026.4.4 → 2026.4.5
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 +84 -1
- package/LICENSE +0 -0
- package/README.md +40 -0
- package/dist/__tests__/backend-contract.test.d.ts +13 -0
- package/dist/__tests__/backend-contract.test.d.ts.map +1 -0
- package/dist/__tests__/backend-contract.test.js +356 -0
- package/dist/__tests__/backend-contract.test.js.map +1 -0
- package/dist/awareness.d.ts +70 -0
- package/dist/awareness.d.ts.map +1 -0
- package/dist/awareness.js +265 -0
- package/dist/awareness.js.map +1 -0
- package/dist/cache.d.ts +0 -0
- package/dist/cache.d.ts.map +0 -0
- package/dist/cache.js +0 -0
- package/dist/cache.js.map +0 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +11 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/llmtxt.d.ts +30 -0
- package/dist/cli/llmtxt.d.ts.map +1 -0
- package/dist/cli/llmtxt.js +478 -0
- package/dist/cli/llmtxt.js.map +1 -0
- package/dist/client.d.ts +0 -0
- package/dist/client.d.ts.map +0 -0
- package/dist/client.js +0 -0
- package/dist/client.js.map +0 -0
- package/dist/compression.d.ts +0 -0
- package/dist/compression.d.ts.map +0 -0
- package/dist/compression.js +0 -0
- package/dist/compression.js.map +0 -0
- package/dist/core/backend.d.ts +554 -0
- package/dist/core/backend.d.ts.map +1 -0
- package/dist/core/backend.js +16 -0
- package/dist/core/backend.js.map +1 -0
- package/dist/crdt-primitives.d.ts +100 -0
- package/dist/crdt-primitives.d.ts.map +1 -0
- package/dist/crdt-primitives.js +173 -0
- package/dist/crdt-primitives.js.map +1 -0
- package/dist/crdt.d.ts +98 -0
- package/dist/crdt.d.ts.map +1 -0
- package/dist/crdt.js +170 -0
- package/dist/crdt.js.map +1 -0
- package/dist/disclosure.d.ts +0 -0
- package/dist/disclosure.d.ts.map +0 -0
- package/dist/disclosure.js +0 -0
- package/dist/disclosure.js.map +0 -0
- package/dist/embeddings.d.ts +82 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +372 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/graph.d.ts +0 -0
- package/dist/graph.d.ts.map +0 -0
- package/dist/graph.js +0 -0
- package/dist/graph.js.map +0 -0
- package/dist/identity.d.ts +102 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +243 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/leases.d.ts +79 -0
- package/dist/leases.d.ts.map +1 -0
- package/dist/leases.js +172 -0
- package/dist/leases.js.map +1 -0
- package/dist/local/index.d.ts +11 -0
- package/dist/local/index.d.ts.map +1 -0
- package/dist/local/index.js +10 -0
- package/dist/local/index.js.map +1 -0
- package/dist/local/local-backend.d.ts +120 -0
- package/dist/local/local-backend.d.ts.map +1 -0
- package/dist/local/local-backend.js +1193 -0
- package/dist/local/local-backend.js.map +1 -0
- package/dist/local/migrations/20260416054148_wandering_paibok/migration.sql +168 -0
- package/dist/local/migrations/20260416054148_wandering_paibok/snapshot.json +1593 -0
- package/dist/local/schema-local.d.ts +4107 -0
- package/dist/local/schema-local.d.ts.map +1 -0
- package/dist/local/schema-local.js +333 -0
- package/dist/local/schema-local.js.map +1 -0
- package/dist/merge.d.ts +0 -0
- package/dist/merge.d.ts.map +0 -0
- package/dist/merge.js +0 -0
- package/dist/merge.js.map +0 -0
- package/dist/patch.d.ts +0 -0
- package/dist/patch.d.ts.map +0 -0
- package/dist/patch.js +0 -0
- package/dist/patch.js.map +0 -0
- package/dist/remote/index.d.ts +10 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +9 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/remote/remote-backend.d.ts +105 -0
- package/dist/remote/remote-backend.d.ts.map +1 -0
- package/dist/remote/remote-backend.js +547 -0
- package/dist/remote/remote-backend.js.map +1 -0
- package/dist/schemas.d.ts +31 -85
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +2 -2
- package/dist/schemas.js.map +1 -1
- package/dist/sdk/a2a.d.ts +132 -0
- package/dist/sdk/a2a.d.ts.map +1 -0
- package/dist/sdk/a2a.js +246 -0
- package/dist/sdk/a2a.js.map +1 -0
- package/dist/sdk/attribution.d.ts +0 -0
- package/dist/sdk/attribution.d.ts.map +0 -0
- package/dist/sdk/attribution.js +0 -0
- package/dist/sdk/attribution.js.map +0 -0
- package/dist/sdk/bft.d.ts +94 -0
- package/dist/sdk/bft.d.ts.map +1 -0
- package/dist/sdk/bft.js +99 -0
- package/dist/sdk/bft.js.map +1 -0
- package/dist/sdk/consensus.d.ts +0 -0
- package/dist/sdk/consensus.d.ts.map +0 -0
- package/dist/sdk/consensus.js +0 -0
- package/dist/sdk/consensus.js.map +0 -0
- package/dist/sdk/document.d.ts +0 -0
- package/dist/sdk/document.d.ts.map +0 -0
- package/dist/sdk/document.js +0 -0
- package/dist/sdk/document.js.map +0 -0
- package/dist/sdk/index.d.ts +6 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +3 -0
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/lifecycle.d.ts +0 -0
- package/dist/sdk/lifecycle.d.ts.map +0 -0
- package/dist/sdk/lifecycle.js +0 -0
- package/dist/sdk/lifecycle.js.map +0 -0
- package/dist/sdk/retrieval.d.ts +0 -0
- package/dist/sdk/retrieval.d.ts.map +0 -0
- package/dist/sdk/retrieval.js +0 -0
- package/dist/sdk/retrieval.js.map +0 -0
- package/dist/sdk/scratchpad.d.ts +91 -0
- package/dist/sdk/scratchpad.d.ts.map +1 -0
- package/dist/sdk/scratchpad.js +144 -0
- package/dist/sdk/scratchpad.js.map +1 -0
- package/dist/sdk/storage-adapter.d.ts +0 -0
- package/dist/sdk/storage-adapter.d.ts.map +0 -0
- package/dist/sdk/storage-adapter.js +0 -0
- package/dist/sdk/storage-adapter.js.map +0 -0
- package/dist/sdk/storage.d.ts +0 -0
- package/dist/sdk/storage.d.ts.map +0 -0
- package/dist/sdk/storage.js +0 -0
- package/dist/sdk/storage.js.map +0 -0
- package/dist/sdk/versions.d.ts +0 -0
- package/dist/sdk/versions.d.ts.map +0 -0
- package/dist/sdk/versions.js +0 -0
- package/dist/sdk/versions.js.map +0 -0
- package/dist/signed-url.d.ts +0 -0
- package/dist/signed-url.d.ts.map +0 -0
- package/dist/signed-url.js +0 -0
- package/dist/signed-url.js.map +0 -0
- package/dist/similarity.d.ts +0 -0
- package/dist/similarity.d.ts.map +0 -0
- package/dist/similarity.js +0 -0
- package/dist/similarity.js.map +0 -0
- package/dist/snapshot.d.ts +0 -0
- package/dist/snapshot.d.ts.map +0 -0
- package/dist/snapshot.js +0 -0
- package/dist/snapshot.js.map +0 -0
- package/dist/subscriptions.d.ts +79 -0
- package/dist/subscriptions.d.ts.map +1 -0
- package/dist/subscriptions.js +122 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/types.d.ts +0 -0
- package/dist/types.d.ts.map +0 -0
- package/dist/types.js +0 -0
- package/dist/types.js.map +0 -0
- package/dist/validation.d.ts +0 -0
- package/dist/validation.d.ts.map +0 -0
- package/dist/validation.js +1 -1
- package/dist/validation.js.map +0 -0
- package/dist/wasm.d.ts +0 -0
- package/dist/wasm.d.ts.map +0 -0
- package/dist/wasm.js +0 -0
- package/dist/wasm.js.map +0 -0
- package/dist/watch.d.ts +68 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +190 -0
- package/dist/watch.js.map +1 -0
- package/package.json +54 -15
- package/wasm/LICENSE +0 -0
- package/wasm/README.md +0 -0
- package/wasm/llmtxt_core.d.ts +80 -0
- package/wasm/llmtxt_core.js +325 -0
- package/wasm/llmtxt_core_bg.wasm +0 -0
- package/wasm/llmtxt_core_bg.wasm.d.ts +47 -38
- package/wasm/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,84 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2026.4.5] - 2026-04-16
|
|
11
|
+
|
|
12
|
+
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`.
|
|
13
|
+
|
|
14
|
+
### Added — Portable SDK / LocalBackend (T317)
|
|
15
|
+
|
|
16
|
+
**T332: RemoteBackend** (`llmtxt/remote`) — thin HTTP/WS client implementing the
|
|
17
|
+
full `Backend` interface. REST for CRUD, SSE for `subscribeStream`, WebSocket for
|
|
18
|
+
`subscribeSection`. Drop-in replacement for `LocalBackend` for remote deployments.
|
|
19
|
+
|
|
20
|
+
**T333: Backend contract test suite** — 25-test parameterised harness that
|
|
21
|
+
validates any `Backend` implementation against the full interface contract.
|
|
22
|
+
Covers documents, versions, lifecycle transitions, events, leases, scratchpad,
|
|
23
|
+
A2A, identity, and nonces.
|
|
24
|
+
|
|
25
|
+
**T334: Fastify LocalBackend plugin** (`apps/backend/src/plugins/local-backend-plugin.ts`)
|
|
26
|
+
— Fastify plugin that decorates the app with `fastify.localBackend`. New routes
|
|
27
|
+
can use the portable SDK without touching the existing Drizzle/Postgres layer.
|
|
28
|
+
|
|
29
|
+
**T335 + T336: `llmtxt` CLI binary** — `packages/llmtxt/src/cli/llmtxt.ts`
|
|
30
|
+
compiled to `dist/cli/llmtxt.js` and listed in `package.json bin`. Commands:
|
|
31
|
+
`init` (SQLite + Ed25519 keypair), `create-doc`, `push-version`, `pull`, `watch`,
|
|
32
|
+
`search`, `keys generate|list|revoke`, `sync`. Defaults to `LocalBackend`; use
|
|
33
|
+
`--remote <url>` for `RemoteBackend`.
|
|
34
|
+
|
|
35
|
+
**T337: `llmtxt sync`** — pulls remote events/documents not in local, pushes
|
|
36
|
+
local documents/events not in remote. State vector exchange for CRDT sections.
|
|
37
|
+
|
|
38
|
+
**T338: CLEO integration example** (`apps/examples/cleo-integration/index.ts`)
|
|
39
|
+
— runnable end-to-end example showing 4 patterns: task attachment docs, BFT
|
|
40
|
+
decision records, A2A coordination, real-time presence.
|
|
41
|
+
|
|
42
|
+
**T339: Docs** (`apps/docs/content/docs/embed/cleo-pm.mdx`) — documentation
|
|
43
|
+
page covering all 4 CLEO + LLMtxt integration patterns with working snippets.
|
|
44
|
+
|
|
45
|
+
**T340: Subpath exports** — `llmtxt/local`, `llmtxt/remote`, `llmtxt/cli` added
|
|
46
|
+
to `package.json` exports map with `types` + `import` entries.
|
|
47
|
+
|
|
48
|
+
**Build**: `build` script now copies `src/local/migrations` into `dist/local/migrations`
|
|
49
|
+
so the CLI and embedded consumers find migrations at runtime.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **Migration idempotency** (7df5795): W2 leases (`20260416021212_natural_shiva`) and W3 BFT/A2A inbox (`20260416030000_w3_bft_a2a_inbox`) Postgres migrations are now fully idempotent — all `CREATE TABLE` / `CREATE INDEX` / `ADD CONSTRAINT` statements use `IF NOT EXISTS` guards and a redundant `ALTER TABLE` that caused Railway crash-loops on retry is removed.
|
|
54
|
+
|
|
55
|
+
## [2026.4.4] - 2026-04-15
|
|
56
|
+
|
|
57
|
+
### Changed — SDK-First Refactor (T111)
|
|
58
|
+
|
|
59
|
+
All 22 violations from `docs/SSOT-AUDIT.md` resolved. `crates/llmtxt-core` is now the canonical Single Source of Truth (SSoT) for all portable primitives. `packages/llmtxt` is a thin WASM wrapper + TypeScript types. `apps/backend` imports only from the SDK — no more direct `node:crypto`, no more pure-TS re-implementations.
|
|
60
|
+
|
|
61
|
+
**Rust primitives added to `crates/llmtxt-core`** (WASM-exported via `packages/llmtxt`):
|
|
62
|
+
- `crypto::sign_webhook_payload` (HMAC-SHA256 for webhook signing) — replaces backend `createHmac`
|
|
63
|
+
- `normalize::l2_normalize` (L2 vector normalization) — replaces backend inline TS
|
|
64
|
+
- `slugify::slugify` — replaces backend inline TS
|
|
65
|
+
- `rbac` module (ROLE_PERMISSIONS matrix lookups) — replaces backend matrix + types
|
|
66
|
+
- `validation` module (`detect_format`, `contains_binary_content`, `find_overlong_line`) — replaces pure-TS re-implementations
|
|
67
|
+
- `graph` module (mentions, tags, directives, graph build + top rankings) — replaces pure-TS `graph.ts`
|
|
68
|
+
- `similarity` module (n-grams, jaccard, text/content similarity, min-hash, rank_by_similarity) — replaces pure-TS `similarity.ts`
|
|
69
|
+
- `disclosure` module with submodules (markdown/code/json/text parsers, search, jsonpath, generateOverview) — replaces pure-TS `disclosure.ts` (729 LoC → ~100 LoC wrapper)
|
|
70
|
+
- `tfidf` module (FNV1a hashing + TF-IDF batch embed) — replaces backend `LocalEmbeddingProvider`
|
|
71
|
+
|
|
72
|
+
**TypeScript types/constants now exported from `packages/llmtxt`**:
|
|
73
|
+
- `DocumentEventType`, `DocumentEvent`, `AuditAction`
|
|
74
|
+
- `Permission`, `DocumentRole`, `OrgRole`, `ROLE_PERMISSIONS`
|
|
75
|
+
- `CONTENT_LIMITS`, `API_VERSION_REGISTRY`, `CURRENT_API_VERSION`, `LATEST_API_VERSION`, `ApiVersionInfo`
|
|
76
|
+
- `VALID_LINK_TYPES`
|
|
77
|
+
- `COLLECTION_EXPORT_SEPARATOR`, `API_KEY_PREFIX`, `API_KEY_LENGTH`, `API_KEY_DISPLAY_LENGTH`
|
|
78
|
+
- `STATE_CHANGING_METHODS` (deduplicated from audit + csrf middleware)
|
|
79
|
+
|
|
80
|
+
### Deferred
|
|
81
|
+
T112 (NAPI-RS native bindings) deferred 2026-04-15 pending production benchmark evidence. WASM is the sole Rust→JS binding for `llmtxt` until benchmarks justify native.
|
|
82
|
+
|
|
83
|
+
### Testing
|
|
84
|
+
- Cargo tests: 122 → 278 (+156 new Rust tests for migrated primitives)
|
|
85
|
+
- Backend tests: 67/67 throughout — zero regression
|
|
86
|
+
- Byte-identity tests: every migrated primitive verified Rust output == previous TypeScript output for ≥3 vectors
|
|
87
|
+
|
|
10
88
|
## [2026.4.3] - 2026-04-13
|
|
11
89
|
|
|
12
90
|
### Added
|
|
@@ -119,7 +197,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
119
197
|
- **cache**: generic LRU cache with configurable TTL, max size, and hit/miss statistics
|
|
120
198
|
- **signed-url**: HMAC-SHA256 signed URL generation and verification -- conversation-scoped, time-limited, with timing-safe comparison
|
|
121
199
|
|
|
122
|
-
[Unreleased]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.
|
|
200
|
+
[Unreleased]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.5...HEAD
|
|
201
|
+
[2026.4.5]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.4...core-v2026.4.5
|
|
202
|
+
[2026.4.4]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.3...core-v2026.4.4
|
|
203
|
+
[2026.4.3]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.2...core-v2026.4.3
|
|
204
|
+
[2026.4.2]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.1...core-v2026.4.2
|
|
205
|
+
[2026.4.1]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.0...core-v2026.4.1
|
|
123
206
|
[2026.4.0]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v2026.4.0
|
|
124
207
|
[2026.3.1]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v2026.3.1
|
|
125
208
|
[2026.3.0]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v2026.3.0
|
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -67,6 +67,46 @@ import { textSimilarity, rankBySimilarity } from 'llmtxt/similarity';
|
|
|
67
67
|
import { buildGraph } from 'llmtxt/graph';
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## LocalBackend (Embedded, Zero-Network)
|
|
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
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Initialise local storage + identity keypair
|
|
98
|
+
llmtxt init
|
|
99
|
+
|
|
100
|
+
# Create a document
|
|
101
|
+
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
|
|
107
|
+
llmtxt sync --remote https://api.llmtxt.my --api-key $KEY
|
|
108
|
+
```
|
|
109
|
+
|
|
70
110
|
## What Ships
|
|
71
111
|
|
|
72
112
|
- Compression, hashing, base62, token estimation (Rust WASM)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend contract test suite.
|
|
3
|
+
*
|
|
4
|
+
* Runs the same set of behavioural assertions against any Backend
|
|
5
|
+
* implementation. Currently validates LocalBackend; RemoteBackend is
|
|
6
|
+
* validated against a mock HTTP server when one is available (skipped
|
|
7
|
+
* in CI without a running server).
|
|
8
|
+
*
|
|
9
|
+
* Pattern: each `describe` block receives a `BackendFactory` and runs
|
|
10
|
+
* identical assertions regardless of which implementation is under test.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=backend-contract.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/backend-contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend contract test suite.
|
|
3
|
+
*
|
|
4
|
+
* Runs the same set of behavioural assertions against any Backend
|
|
5
|
+
* implementation. Currently validates LocalBackend; RemoteBackend is
|
|
6
|
+
* validated against a mock HTTP server when one is available (skipped
|
|
7
|
+
* in CI without a running server).
|
|
8
|
+
*
|
|
9
|
+
* Pattern: each `describe` block receives a `BackendFactory` and runs
|
|
10
|
+
* identical assertions regardless of which implementation is under test.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it, before, after } from 'node:test';
|
|
13
|
+
import assert from 'node:assert/strict';
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import { LocalBackend } from '../local/local-backend.js';
|
|
18
|
+
/**
|
|
19
|
+
* Make a temp dir for each test backend instance so tests are isolated.
|
|
20
|
+
*/
|
|
21
|
+
function makeTempDir() {
|
|
22
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'llmtxt-contract-'));
|
|
23
|
+
}
|
|
24
|
+
// ── Contract suite factory ────────────────────────────────────────
|
|
25
|
+
function runContractSuite(label, factory) {
|
|
26
|
+
describe(`${label} — Backend contract`, () => {
|
|
27
|
+
let backend;
|
|
28
|
+
let cleanup;
|
|
29
|
+
before(async () => {
|
|
30
|
+
({ backend, cleanup } = factory());
|
|
31
|
+
await backend.open();
|
|
32
|
+
});
|
|
33
|
+
after(async () => {
|
|
34
|
+
await backend.close();
|
|
35
|
+
await cleanup();
|
|
36
|
+
});
|
|
37
|
+
// ── Document CRUD ────────────────────────────────────────────
|
|
38
|
+
describe('createDocument / getDocument', () => {
|
|
39
|
+
it('creates a document and retrieves it by id', async () => {
|
|
40
|
+
const doc = await backend.createDocument({
|
|
41
|
+
title: 'Contract Test Doc',
|
|
42
|
+
createdBy: 'test-agent',
|
|
43
|
+
});
|
|
44
|
+
assert.ok(doc.id, 'document id must be truthy');
|
|
45
|
+
assert.equal(doc.title, 'Contract Test Doc');
|
|
46
|
+
assert.equal(doc.createdBy, 'test-agent');
|
|
47
|
+
assert.equal(doc.state, 'DRAFT');
|
|
48
|
+
assert.equal(doc.versionCount, 0);
|
|
49
|
+
const fetched = await backend.getDocument(doc.id);
|
|
50
|
+
assert.ok(fetched, 'getDocument must return the document');
|
|
51
|
+
assert.equal(fetched.id, doc.id);
|
|
52
|
+
assert.equal(fetched.title, doc.title);
|
|
53
|
+
});
|
|
54
|
+
it('getDocument returns null for unknown id', async () => {
|
|
55
|
+
const result = await backend.getDocument('nonexistent-id-xyz');
|
|
56
|
+
assert.equal(result, null, 'must return null for missing document');
|
|
57
|
+
});
|
|
58
|
+
it('generates a unique slug from the title', async () => {
|
|
59
|
+
const doc = await backend.createDocument({
|
|
60
|
+
title: 'Slug Test Document',
|
|
61
|
+
createdBy: 'agent',
|
|
62
|
+
});
|
|
63
|
+
assert.ok(doc.slug, 'slug must be set');
|
|
64
|
+
assert.match(doc.slug, /^[a-z0-9-]+$/, 'slug must be url-safe');
|
|
65
|
+
});
|
|
66
|
+
it('accepts an explicit slug', async () => {
|
|
67
|
+
const doc = await backend.createDocument({
|
|
68
|
+
title: 'Explicit Slug Doc',
|
|
69
|
+
createdBy: 'agent',
|
|
70
|
+
slug: 'my-explicit-slug',
|
|
71
|
+
});
|
|
72
|
+
assert.equal(doc.slug, 'my-explicit-slug');
|
|
73
|
+
});
|
|
74
|
+
it('getDocumentBySlug retrieves a document', async () => {
|
|
75
|
+
const doc = await backend.createDocument({
|
|
76
|
+
title: 'Slug Lookup Test',
|
|
77
|
+
createdBy: 'agent',
|
|
78
|
+
slug: 'slug-lookup-unique',
|
|
79
|
+
});
|
|
80
|
+
const found = await backend.getDocumentBySlug('slug-lookup-unique');
|
|
81
|
+
assert.ok(found);
|
|
82
|
+
assert.equal(found.id, doc.id);
|
|
83
|
+
});
|
|
84
|
+
it('getDocumentBySlug returns null for unknown slug', async () => {
|
|
85
|
+
const result = await backend.getDocumentBySlug('does-not-exist');
|
|
86
|
+
assert.equal(result, null);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('listDocuments', () => {
|
|
90
|
+
it('returns documents with pagination', async () => {
|
|
91
|
+
const result = await backend.listDocuments({ limit: 100 });
|
|
92
|
+
assert.ok(Array.isArray(result.items));
|
|
93
|
+
assert.ok(result.items.length >= 1, 'at least one document from prior tests');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('deleteDocument', () => {
|
|
97
|
+
it('deletes an existing document and returns true', async () => {
|
|
98
|
+
const doc = await backend.createDocument({
|
|
99
|
+
title: 'Delete Me',
|
|
100
|
+
createdBy: 'agent',
|
|
101
|
+
});
|
|
102
|
+
const deleted = await backend.deleteDocument(doc.id);
|
|
103
|
+
assert.equal(deleted, true);
|
|
104
|
+
const fetched = await backend.getDocument(doc.id);
|
|
105
|
+
assert.equal(fetched, null, 'must not exist after deletion');
|
|
106
|
+
});
|
|
107
|
+
it('returns false for nonexistent document', async () => {
|
|
108
|
+
const result = await backend.deleteDocument('never-existed');
|
|
109
|
+
assert.equal(result, false);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
// ── Versions ─────────────────────────────────────────────────
|
|
113
|
+
describe('publishVersion / getVersion / listVersions', () => {
|
|
114
|
+
it('publishes and retrieves a version', async () => {
|
|
115
|
+
const doc = await backend.createDocument({
|
|
116
|
+
title: 'Version Test Doc',
|
|
117
|
+
createdBy: 'agent',
|
|
118
|
+
});
|
|
119
|
+
const version = await backend.publishVersion({
|
|
120
|
+
documentId: doc.id,
|
|
121
|
+
content: '# Hello\n\nThis is version 1.',
|
|
122
|
+
patchText: '',
|
|
123
|
+
createdBy: 'agent',
|
|
124
|
+
changelog: 'Initial version',
|
|
125
|
+
});
|
|
126
|
+
assert.equal(version.versionNumber, 1);
|
|
127
|
+
assert.equal(version.createdBy, 'agent');
|
|
128
|
+
assert.equal(version.changelog, 'Initial version');
|
|
129
|
+
assert.ok(version.contentHash, 'contentHash must be set');
|
|
130
|
+
const fetched = await backend.getVersion(doc.id, 1);
|
|
131
|
+
assert.ok(fetched);
|
|
132
|
+
assert.equal(fetched.versionNumber, 1);
|
|
133
|
+
assert.equal(fetched.contentHash, version.contentHash);
|
|
134
|
+
});
|
|
135
|
+
it('increments versionCount on the document', async () => {
|
|
136
|
+
const doc = await backend.createDocument({
|
|
137
|
+
title: 'Version Count Test',
|
|
138
|
+
createdBy: 'agent',
|
|
139
|
+
});
|
|
140
|
+
await backend.publishVersion({
|
|
141
|
+
documentId: doc.id,
|
|
142
|
+
content: 'v1',
|
|
143
|
+
patchText: '',
|
|
144
|
+
createdBy: 'agent',
|
|
145
|
+
changelog: 'v1',
|
|
146
|
+
});
|
|
147
|
+
await backend.publishVersion({
|
|
148
|
+
documentId: doc.id,
|
|
149
|
+
content: 'v2',
|
|
150
|
+
patchText: '',
|
|
151
|
+
createdBy: 'agent',
|
|
152
|
+
changelog: 'v2',
|
|
153
|
+
});
|
|
154
|
+
const updated = await backend.getDocument(doc.id);
|
|
155
|
+
assert.ok(updated);
|
|
156
|
+
assert.equal(updated.versionCount, 2);
|
|
157
|
+
});
|
|
158
|
+
it('getVersion returns null for unknown version', async () => {
|
|
159
|
+
const doc = await backend.createDocument({
|
|
160
|
+
title: 'Version Null Test',
|
|
161
|
+
createdBy: 'agent',
|
|
162
|
+
});
|
|
163
|
+
const result = await backend.getVersion(doc.id, 999);
|
|
164
|
+
assert.equal(result, null);
|
|
165
|
+
});
|
|
166
|
+
it('listVersions returns all versions in order', async () => {
|
|
167
|
+
const doc = await backend.createDocument({
|
|
168
|
+
title: 'List Versions Test',
|
|
169
|
+
createdBy: 'agent',
|
|
170
|
+
});
|
|
171
|
+
await backend.publishVersion({ documentId: doc.id, content: 'v1', patchText: '', createdBy: 'agent', changelog: 'v1' });
|
|
172
|
+
await backend.publishVersion({ documentId: doc.id, content: 'v2', patchText: '', createdBy: 'agent', changelog: 'v2' });
|
|
173
|
+
const versions = await backend.listVersions(doc.id);
|
|
174
|
+
assert.equal(versions.length, 2);
|
|
175
|
+
assert.equal(versions[0].versionNumber, 1);
|
|
176
|
+
assert.equal(versions[1].versionNumber, 2);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
describe('transitionVersion', () => {
|
|
180
|
+
it('transitions DRAFT → REVIEW', async () => {
|
|
181
|
+
const doc = await backend.createDocument({
|
|
182
|
+
title: 'Lifecycle Transition Test',
|
|
183
|
+
createdBy: 'agent',
|
|
184
|
+
});
|
|
185
|
+
const result = await backend.transitionVersion({
|
|
186
|
+
documentId: doc.id,
|
|
187
|
+
to: 'REVIEW',
|
|
188
|
+
changedBy: 'agent',
|
|
189
|
+
});
|
|
190
|
+
assert.equal(result.success, true);
|
|
191
|
+
assert.ok(result.document);
|
|
192
|
+
assert.equal(result.document.state, 'REVIEW');
|
|
193
|
+
});
|
|
194
|
+
it('rejects invalid transitions', async () => {
|
|
195
|
+
const doc = await backend.createDocument({
|
|
196
|
+
title: 'Invalid Transition Test',
|
|
197
|
+
createdBy: 'agent',
|
|
198
|
+
});
|
|
199
|
+
// DRAFT → ARCHIVED is not a valid direct transition
|
|
200
|
+
const result = await backend.transitionVersion({
|
|
201
|
+
documentId: doc.id,
|
|
202
|
+
to: 'ARCHIVED',
|
|
203
|
+
changedBy: 'agent',
|
|
204
|
+
});
|
|
205
|
+
assert.equal(result.success, false);
|
|
206
|
+
assert.ok(result.error, 'error message must be provided');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
// ── Events ───────────────────────────────────────────────────
|
|
210
|
+
describe('appendEvent / queryEvents', () => {
|
|
211
|
+
it('appends and queries events', async () => {
|
|
212
|
+
const doc = await backend.createDocument({
|
|
213
|
+
title: 'Event Test Doc',
|
|
214
|
+
createdBy: 'agent',
|
|
215
|
+
});
|
|
216
|
+
const event = await backend.appendEvent({
|
|
217
|
+
documentId: doc.id,
|
|
218
|
+
type: 'test.event',
|
|
219
|
+
agentId: 'agent',
|
|
220
|
+
payload: { foo: 'bar' },
|
|
221
|
+
});
|
|
222
|
+
assert.ok(event.id);
|
|
223
|
+
assert.equal(event.documentId, doc.id);
|
|
224
|
+
assert.equal(event.type, 'test.event');
|
|
225
|
+
assert.deepEqual(event.payload, { foo: 'bar' });
|
|
226
|
+
const result = await backend.queryEvents({ documentId: doc.id });
|
|
227
|
+
assert.ok(result.items.length >= 1);
|
|
228
|
+
assert.equal(result.items[0].type, 'test.event');
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
// ── Leases ───────────────────────────────────────────────────
|
|
232
|
+
describe('acquireLease / renewLease / releaseLease / getLease', () => {
|
|
233
|
+
it('acquires, checks, and releases a lease', async () => {
|
|
234
|
+
const resource = `test-resource-${Date.now()}`;
|
|
235
|
+
const lease = await backend.acquireLease({
|
|
236
|
+
resource,
|
|
237
|
+
holder: 'agent-1',
|
|
238
|
+
ttlMs: 5000,
|
|
239
|
+
});
|
|
240
|
+
assert.ok(lease, 'lease must be acquired');
|
|
241
|
+
assert.equal(lease.resource, resource);
|
|
242
|
+
assert.equal(lease.holder, 'agent-1');
|
|
243
|
+
const fetched = await backend.getLease(resource);
|
|
244
|
+
assert.ok(fetched);
|
|
245
|
+
assert.equal(fetched.holder, 'agent-1');
|
|
246
|
+
const released = await backend.releaseLease(resource, 'agent-1');
|
|
247
|
+
assert.equal(released, true);
|
|
248
|
+
const afterRelease = await backend.getLease(resource);
|
|
249
|
+
assert.equal(afterRelease, null);
|
|
250
|
+
});
|
|
251
|
+
it('blocks second agent from acquiring held lease', async () => {
|
|
252
|
+
const resource = `contested-${Date.now()}`;
|
|
253
|
+
await backend.acquireLease({ resource, holder: 'agent-1', ttlMs: 5000 });
|
|
254
|
+
const second = await backend.acquireLease({ resource, holder: 'agent-2', ttlMs: 5000 });
|
|
255
|
+
assert.equal(second, null, 'second agent must not acquire a held lease');
|
|
256
|
+
await backend.releaseLease(resource, 'agent-1');
|
|
257
|
+
});
|
|
258
|
+
it('allows same holder to re-acquire (idempotent)', async () => {
|
|
259
|
+
const resource = `reacquire-${Date.now()}`;
|
|
260
|
+
const first = await backend.acquireLease({ resource, holder: 'agent-1', ttlMs: 5000 });
|
|
261
|
+
const second = await backend.acquireLease({ resource, holder: 'agent-1', ttlMs: 5000 });
|
|
262
|
+
assert.ok(first);
|
|
263
|
+
assert.ok(second, 'same holder re-acquire must succeed');
|
|
264
|
+
await backend.releaseLease(resource, 'agent-1');
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
// ── Scratchpad ───────────────────────────────────────────────
|
|
268
|
+
describe('sendScratchpad / pollScratchpad / deleteScratchpadMessage', () => {
|
|
269
|
+
it('sends and polls a scratchpad message', async () => {
|
|
270
|
+
const msg = await backend.sendScratchpad({
|
|
271
|
+
toAgentId: 'rx-agent',
|
|
272
|
+
fromAgentId: 'tx-agent',
|
|
273
|
+
payload: { task: 'do the thing' },
|
|
274
|
+
});
|
|
275
|
+
assert.ok(msg.id);
|
|
276
|
+
assert.equal(msg.toAgentId, 'rx-agent');
|
|
277
|
+
assert.deepEqual(msg.payload, { task: 'do the thing' });
|
|
278
|
+
const polled = await backend.pollScratchpad('rx-agent');
|
|
279
|
+
const found = polled.find((m) => m.id === msg.id);
|
|
280
|
+
assert.ok(found, 'message must be pollable');
|
|
281
|
+
const deleted = await backend.deleteScratchpadMessage(msg.id, 'rx-agent');
|
|
282
|
+
assert.equal(deleted, true);
|
|
283
|
+
const afterDelete = await backend.pollScratchpad('rx-agent');
|
|
284
|
+
const stillThere = afterDelete.find((m) => m.id === msg.id);
|
|
285
|
+
assert.equal(stillThere, undefined, 'message must not appear after deletion');
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
// ── A2A ──────────────────────────────────────────────────────
|
|
289
|
+
describe('sendA2AMessage / pollA2AInbox / deleteA2AMessage', () => {
|
|
290
|
+
it('delivers and polls an A2A message', async () => {
|
|
291
|
+
const sent = await backend.sendA2AMessage({
|
|
292
|
+
toAgentId: 'target-agent',
|
|
293
|
+
envelopeJson: JSON.stringify({ op: 'ping', from: 'sender' }),
|
|
294
|
+
});
|
|
295
|
+
assert.equal(sent.success, true);
|
|
296
|
+
assert.ok(sent.message);
|
|
297
|
+
assert.equal(sent.message.toAgentId, 'target-agent');
|
|
298
|
+
const inbox = await backend.pollA2AInbox('target-agent');
|
|
299
|
+
const found = inbox.find((m) => m.id === sent.message.id);
|
|
300
|
+
assert.ok(found);
|
|
301
|
+
const deleted = await backend.deleteA2AMessage(sent.message.id, 'target-agent');
|
|
302
|
+
assert.equal(deleted, true);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
// ── Identity ─────────────────────────────────────────────────
|
|
306
|
+
describe('registerAgentPubkey / lookupAgentPubkey / revokeAgentPubkey', () => {
|
|
307
|
+
it('registers, looks up, and revokes a pubkey', async () => {
|
|
308
|
+
const agentId = `agent-${Date.now()}`;
|
|
309
|
+
const pubkeyHex = 'a'.repeat(64); // fake but syntactically valid
|
|
310
|
+
const record = await backend.registerAgentPubkey(agentId, pubkeyHex, 'Test Key');
|
|
311
|
+
assert.equal(record.agentId, agentId);
|
|
312
|
+
assert.equal(record.pubkeyHex, pubkeyHex);
|
|
313
|
+
const fetched = await backend.lookupAgentPubkey(agentId);
|
|
314
|
+
assert.ok(fetched);
|
|
315
|
+
assert.equal(fetched.agentId, agentId);
|
|
316
|
+
const revoked = await backend.revokeAgentPubkey(agentId, pubkeyHex);
|
|
317
|
+
assert.equal(revoked, true);
|
|
318
|
+
});
|
|
319
|
+
it('registerAgentPubkey is idempotent', async () => {
|
|
320
|
+
const agentId = `idem-agent-${Date.now()}`;
|
|
321
|
+
const pubkeyHex = 'b'.repeat(64);
|
|
322
|
+
await backend.registerAgentPubkey(agentId, pubkeyHex);
|
|
323
|
+
const second = await backend.registerAgentPubkey(agentId, pubkeyHex);
|
|
324
|
+
assert.equal(second.agentId, agentId, 'idempotent: no error on second call');
|
|
325
|
+
});
|
|
326
|
+
it('lookupAgentPubkey returns null for unregistered agent', async () => {
|
|
327
|
+
const result = await backend.lookupAgentPubkey('never-registered');
|
|
328
|
+
assert.equal(result, null);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
describe('recordSignatureNonce / hasNonceBeenUsed', () => {
|
|
332
|
+
it('records and checks nonces', async () => {
|
|
333
|
+
const agentId = `nonce-agent-${Date.now()}`;
|
|
334
|
+
const nonce = `nonce-${Date.now()}`;
|
|
335
|
+
const first = await backend.recordSignatureNonce(agentId, nonce);
|
|
336
|
+
assert.equal(first, true, 'first recording must succeed');
|
|
337
|
+
const second = await backend.recordSignatureNonce(agentId, nonce);
|
|
338
|
+
assert.equal(second, false, 'duplicate nonce must be rejected');
|
|
339
|
+
const used = await backend.hasNonceBeenUsed(agentId, nonce);
|
|
340
|
+
assert.equal(used, true);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
// ── Run contract suite against LocalBackend ───────────────────────
|
|
346
|
+
runContractSuite('LocalBackend', () => {
|
|
347
|
+
const dir = makeTempDir();
|
|
348
|
+
const backend = new LocalBackend({ storagePath: dir });
|
|
349
|
+
return {
|
|
350
|
+
backend,
|
|
351
|
+
cleanup: async () => {
|
|
352
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
});
|
|
356
|
+
//# sourceMappingURL=backend-contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-contract.test.js","sourceRoot":"","sources":["../../src/__tests__/backend-contract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Awareness SDK module — T257.
|
|
3
|
+
*
|
|
4
|
+
* Implements the setLocalAwarenessState / onAwarenessChange / getAwarenessStates
|
|
5
|
+
* surface over a raw WebSocket connection.
|
|
6
|
+
*
|
|
7
|
+
* The y-protocols/awareness library is used for encoding/decoding awareness
|
|
8
|
+
* update messages (CRDT-aware awareness protocol). Since direct yjs imports are
|
|
9
|
+
* banned by the SSoT lint rule, this module relies on the re-exported
|
|
10
|
+
* primitives from the llmtxt SDK (which wraps the WASM core).
|
|
11
|
+
*
|
|
12
|
+
* Awareness message framing on the wire:
|
|
13
|
+
* Byte 0 = 0x03 (MSG_AWARENESS_RELAY, matching ws-crdt.ts constant)
|
|
14
|
+
* Bytes 1..N = raw y-protocols awareness update bytes
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Presence state for a single agent.
|
|
18
|
+
*/
|
|
19
|
+
export interface AwarenessState {
|
|
20
|
+
agentId: string;
|
|
21
|
+
section: string;
|
|
22
|
+
cursorOffset?: number;
|
|
23
|
+
lastSeen: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Events emitted when awareness state changes.
|
|
27
|
+
*/
|
|
28
|
+
export type AwarenessEventType = 'JOIN' | 'LEAVE' | 'MOVE';
|
|
29
|
+
export interface AwarenessEvent {
|
|
30
|
+
type: AwarenessEventType;
|
|
31
|
+
clientId: number;
|
|
32
|
+
state: AwarenessState | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Unsubscribe function returned by onAwarenessChange.
|
|
36
|
+
*/
|
|
37
|
+
export type Unsubscribe = () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Set the local agent's awareness state on a WebSocket connection.
|
|
40
|
+
* Encodes the state and sends it to the server (which relays to peers).
|
|
41
|
+
*
|
|
42
|
+
* @param conn Active WebSocket connection.
|
|
43
|
+
* @param state The awareness state to broadcast.
|
|
44
|
+
*/
|
|
45
|
+
export declare function setLocalAwarenessState(conn: WebSocket | {
|
|
46
|
+
send(data: Uint8Array | Buffer): void;
|
|
47
|
+
}, state: AwarenessState): void;
|
|
48
|
+
/**
|
|
49
|
+
* Subscribe to awareness state changes on a WebSocket connection.
|
|
50
|
+
* The callback is invoked with the full current state map whenever
|
|
51
|
+
* a peer's awareness changes.
|
|
52
|
+
*
|
|
53
|
+
* @param conn Active WebSocket connection.
|
|
54
|
+
* @param fn Callback invoked with updated Map<clientId, AwarenessState>.
|
|
55
|
+
* @returns Unsubscribe function.
|
|
56
|
+
*/
|
|
57
|
+
export declare function onAwarenessChange(conn: WebSocket | {
|
|
58
|
+
on?(event: string, handler: (data: Buffer | Uint8Array) => void): void;
|
|
59
|
+
addEventListener?(type: string, handler: (event: {
|
|
60
|
+
data: unknown;
|
|
61
|
+
}) => void): void;
|
|
62
|
+
}, fn: (states: Map<number, AwarenessState>) => void): Unsubscribe;
|
|
63
|
+
/**
|
|
64
|
+
* Get the current awareness states for all known clients on a connection.
|
|
65
|
+
*
|
|
66
|
+
* @param conn Active WebSocket connection.
|
|
67
|
+
* @returns Map<clientId, AwarenessState>.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getAwarenessStates(conn: WebSocket | object): Map<number, AwarenessState>;
|
|
70
|
+
//# sourceMappingURL=awareness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../src/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAgJrC;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG;IAAE,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CA0B/H;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,GAAG;IAAE,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAA;CAAE,EAChL,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,KAAK,IAAI,GAChD,WAAW,CA6Eb;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAExF"}
|