llmtxt 2026.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +21 -0
  3. package/README.md +64 -0
  4. package/dist/cache.d.ts +155 -0
  5. package/dist/cache.d.ts.map +1 -0
  6. package/dist/cache.js +193 -0
  7. package/dist/cache.js.map +1 -0
  8. package/dist/client.d.ts +80 -0
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +143 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/compression.d.ts +9 -0
  13. package/dist/compression.d.ts.map +1 -0
  14. package/dist/compression.js +8 -0
  15. package/dist/compression.js.map +1 -0
  16. package/dist/disclosure.d.ts +215 -0
  17. package/dist/disclosure.d.ts.map +1 -0
  18. package/dist/disclosure.js +532 -0
  19. package/dist/disclosure.js.map +1 -0
  20. package/dist/graph.d.ts +76 -0
  21. package/dist/graph.d.ts.map +1 -0
  22. package/dist/graph.js +137 -0
  23. package/dist/graph.js.map +1 -0
  24. package/dist/index.d.ts +38 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +31 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/patch.d.ts +8 -0
  29. package/dist/patch.d.ts.map +1 -0
  30. package/dist/patch.js +8 -0
  31. package/dist/patch.js.map +1 -0
  32. package/dist/schemas.d.ts +290 -0
  33. package/dist/schemas.d.ts.map +1 -0
  34. package/dist/schemas.js +154 -0
  35. package/dist/schemas.js.map +1 -0
  36. package/dist/sdk/attribution.d.ts +59 -0
  37. package/dist/sdk/attribution.d.ts.map +1 -0
  38. package/dist/sdk/attribution.js +99 -0
  39. package/dist/sdk/attribution.js.map +1 -0
  40. package/dist/sdk/consensus.d.ts +73 -0
  41. package/dist/sdk/consensus.d.ts.map +1 -0
  42. package/dist/sdk/consensus.js +110 -0
  43. package/dist/sdk/consensus.js.map +1 -0
  44. package/dist/sdk/document.d.ts +92 -0
  45. package/dist/sdk/document.d.ts.map +1 -0
  46. package/dist/sdk/document.js +182 -0
  47. package/dist/sdk/document.js.map +1 -0
  48. package/dist/sdk/index.d.ts +22 -0
  49. package/dist/sdk/index.d.ts.map +1 -0
  50. package/dist/sdk/index.js +15 -0
  51. package/dist/sdk/index.js.map +1 -0
  52. package/dist/sdk/lifecycle.d.ts +66 -0
  53. package/dist/sdk/lifecycle.d.ts.map +1 -0
  54. package/dist/sdk/lifecycle.js +80 -0
  55. package/dist/sdk/lifecycle.js.map +1 -0
  56. package/dist/sdk/retrieval.d.ts +64 -0
  57. package/dist/sdk/retrieval.d.ts.map +1 -0
  58. package/dist/sdk/retrieval.js +102 -0
  59. package/dist/sdk/retrieval.js.map +1 -0
  60. package/dist/sdk/storage-adapter.d.ts +53 -0
  61. package/dist/sdk/storage-adapter.d.ts.map +1 -0
  62. package/dist/sdk/storage-adapter.js +2 -0
  63. package/dist/sdk/storage-adapter.js.map +1 -0
  64. package/dist/sdk/storage.d.ts +86 -0
  65. package/dist/sdk/storage.d.ts.map +1 -0
  66. package/dist/sdk/storage.js +69 -0
  67. package/dist/sdk/storage.js.map +1 -0
  68. package/dist/sdk/versions.d.ts +107 -0
  69. package/dist/sdk/versions.d.ts.map +1 -0
  70. package/dist/sdk/versions.js +129 -0
  71. package/dist/sdk/versions.js.map +1 -0
  72. package/dist/signed-url.d.ts +90 -0
  73. package/dist/signed-url.d.ts.map +1 -0
  74. package/dist/signed-url.js +159 -0
  75. package/dist/signed-url.js.map +1 -0
  76. package/dist/similarity.d.ts +57 -0
  77. package/dist/similarity.d.ts.map +1 -0
  78. package/dist/similarity.js +134 -0
  79. package/dist/similarity.js.map +1 -0
  80. package/dist/snapshot.d.ts +54 -0
  81. package/dist/snapshot.d.ts.map +1 -0
  82. package/dist/snapshot.js +94 -0
  83. package/dist/snapshot.js.map +1 -0
  84. package/dist/types.d.ts +92 -0
  85. package/dist/types.d.ts.map +1 -0
  86. package/dist/types.js +8 -0
  87. package/dist/types.js.map +1 -0
  88. package/dist/validation.d.ts +146 -0
  89. package/dist/validation.d.ts.map +1 -0
  90. package/dist/validation.js +285 -0
  91. package/dist/validation.js.map +1 -0
  92. package/dist/wasm.d.ts +28 -0
  93. package/dist/wasm.d.ts.map +1 -0
  94. package/dist/wasm.js +92 -0
  95. package/dist/wasm.js.map +1 -0
  96. package/package.json +98 -0
  97. package/wasm/LICENSE +21 -0
  98. package/wasm/README.md +63 -0
  99. package/wasm/llmtxt_core.d.ts +176 -0
  100. package/wasm/llmtxt_core.js +719 -0
  101. package/wasm/llmtxt_core_bg.wasm +0 -0
  102. package/wasm/llmtxt_core_bg.wasm.d.ts +37 -0
  103. package/wasm/package.json +25 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,66 @@
1
+ # Changelog
2
+
3
+ All notable changes to `llmtxt` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2026.4.0] - 2026-03-27
11
+
12
+ ### Added
13
+ - **sdk**: `llmtxt/sdk` subpath export with collaborative document primitives
14
+ - **lifecycle**: `DocumentState` enum (DRAFT, REVIEW, LOCKED, ARCHIVED) and pure state transition validator `isValidTransition()`
15
+ - **lifecycle**: `StateTransition` type with full transition metadata (who, when, why, at which version)
16
+ - **versioning**: `VersionEntry` type and `reconstructVersion()` for rebuilding any version from a patch stack
17
+ - **versioning**: `validatePatchApplies()` for pre-flight patch conflict detection
18
+ - **versioning**: `squashPatches()` to compose consecutive patches into one
19
+ - **attribution**: `ContributorSummary` and `VersionAttribution` types with `buildContributorSummary()` and `attributeVersion()` helpers
20
+ - **consensus**: `ApprovalStatus` enum, `Review`, `ApprovalPolicy` types, and `evaluateApprovals()` pure evaluation logic
21
+ - **storage**: `ContentRef` type abstracting inline blobs vs object-store references
22
+ - **retrieval**: `planRetrieval()` token-budget-aware section planning using disclosure primitives
23
+ - **exports**: tree-shakeable subpath exports for `llmtxt/disclosure`, `llmtxt/similarity`, `llmtxt/graph`
24
+
25
+ ### Changed
26
+ - **package**: renamed from `@codluv/llmtxt` to `llmtxt` (unscoped, shorter imports)
27
+ - **structure**: renamed `packages/core/` to `packages/llmtxt/` to match npm package name
28
+ - **description**: updated to reflect SDK capabilities alongside primitives
29
+
30
+ ## [2026.3.1] - 2026-03-27
31
+
32
+ ### Fixed
33
+ - **signed-url**: `verify_signed_url` now treats `exp=0` as "never expires" instead of immediately expired, aligning with `is_expired()` behavior
34
+
35
+ ## [2026.3.0] - 2026-03-26
36
+
37
+ ### Added
38
+
39
+ - **patching**: `createPatch` and `applyPatch` unified-diff helpers backed by the Rust core for deterministic attachment versioning workflows
40
+ - **client**: `reshare`, `addVersion`, `addVersionFromContent`, and `createVersionPatch` helpers for attachment lifecycle and version submission
41
+ - **types**: `AttachmentSharingMode`, `AttachmentReshareOptions`, `AttachmentVersionOptions`, and `AttachmentVersionResult` support for consumers integrating attachment APIs
42
+
43
+ ### Changed
44
+
45
+ - **versioning**: adopt unified ecosystem CalVer across the Rust crate, WASM artifacts, and TypeScript package consumers using a Cargo-safe `YYYY.M.PATCH` format
46
+ - **client**: keep `resign` as a backward-compatible alias while standardizing on `reshare`
47
+ - **signed-url**: support configurable path prefixes and signature lengths when generating URLs
48
+ - **signed-url**: verify URLs using the actual signature length and final path segment so `/attachments/{slug}` URLs verify correctly
49
+ - **build**: add `build:wasm`, `build:all`, and `validate` scripts for release-ready consumer artifacts
50
+
51
+ ## Legacy [0.4.0] - 2026-03-23
52
+
53
+ ### Added
54
+
55
+ - **compression**: deflate compress/decompress, base62 encoding/decoding, SHA-256 hashing, token estimation, compression ratio calculation
56
+ - **schemas**: Zod validation schemas for JSON/text/markdown formats, `prompt-v1` predefined schema, schema registry with type exports
57
+ - **validation**: format auto-detection, content validation against schemas, `autoValidate` convenience function
58
+ - **disclosure**: progressive disclosure utilities -- document overview generation, section extraction, line-range access, content search (string + regex), JSONPath queries, TOC generation
59
+ - **cache**: generic LRU cache with configurable TTL, max size, and hit/miss statistics
60
+ - **signed-url**: HMAC-SHA256 signed URL generation and verification -- conversation-scoped, time-limited, with timing-safe comparison
61
+
62
+ [Unreleased]: https://github.com/kryptobaseddev/llmtxt/compare/core-v2026.4.0...HEAD
63
+ [2026.4.0]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v2026.4.0
64
+ [2026.3.1]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v2026.3.1
65
+ [2026.3.0]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v2026.3.0
66
+ [0.4.0]: https://github.com/kryptobaseddev/llmtxt/releases/tag/core-v0.4.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Codluv
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # llmtxt
2
+
3
+ Primitives and SDK for LLM agent content workflows.
4
+
5
+ `llmtxt` wraps the Rust `llmtxt-core` crate through WASM so TypeScript
6
+ consumers use the same single-source-of-truth logic as native Rust consumers.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install llmtxt
12
+ ```
13
+
14
+ ## Primitives
15
+
16
+ ```ts
17
+ import {
18
+ compress, decompress, generateId, hashContent,
19
+ createPatch, applyPatch, generateSignedUrl,
20
+ } from 'llmtxt';
21
+
22
+ const compressed = await compress('Hello world');
23
+ const text = await decompress(compressed);
24
+ const slug = generateId();
25
+ const hash = hashContent(text);
26
+
27
+ const patch = createPatch('hello\n', 'hello world\n');
28
+ const rebuilt = applyPatch('hello\n', patch);
29
+ ```
30
+
31
+ ## SDK (Collaborative Documents)
32
+
33
+ ```ts
34
+ import {
35
+ isValidTransition, evaluateApprovals, planRetrieval,
36
+ reconstructVersion, attributeVersion, buildContributorSummary,
37
+ } from 'llmtxt/sdk';
38
+ ```
39
+
40
+ ### Subpath Exports
41
+
42
+ ```ts
43
+ import { generateOverview, getSection } from 'llmtxt/disclosure';
44
+ import { textSimilarity, rankBySimilarity } from 'llmtxt/similarity';
45
+ import { buildGraph } from 'llmtxt/graph';
46
+ ```
47
+
48
+ ## What Ships
49
+
50
+ - Compression, hashing, base62, token estimation (Rust WASM)
51
+ - Signed URL generation and verification
52
+ - Unified diff patch creation, application, version reconstruction
53
+ - Progressive disclosure: overview, section extraction, content search
54
+ - Collaborative document lifecycle (DRAFT, REVIEW, LOCKED, ARCHIVED)
55
+ - Version stack management with attribution tracking
56
+ - Consensus/approval evaluation with stale review handling
57
+ - Token-budget-aware retrieval planning
58
+ - Storage content reference abstractions (inline vs object-store)
59
+ - Attachment client helpers for upload, fetch, reshare, versioning
60
+
61
+ ## Release Model
62
+
63
+ The npm package includes prebuilt WASM artifacts generated from the Rust crate in
64
+ `crates/llmtxt-core`, so TypeScript and Rust consumers stay aligned on behavior.
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Generic LRU cache with TTL support and hit/miss statistics.
3
+ *
4
+ * Provider-agnostic — no framework dependencies.
5
+ */
6
+ /**
7
+ * Snapshot of cache performance statistics.
8
+ *
9
+ * @remarks
10
+ * Returned by {@link LRUCache.getStats}. The `hitRate` is calculated as
11
+ * `(hits / (hits + misses)) * 100` and rounded to two decimal places.
12
+ */
13
+ export interface CacheStats {
14
+ /** Total number of cache hits since last reset. */
15
+ hits: number;
16
+ /** Total number of cache misses since last reset. */
17
+ misses: number;
18
+ /** Current number of live (non-expired) entries in the cache. */
19
+ size: number;
20
+ /** Maximum number of entries the cache can hold. */
21
+ maxSize: number;
22
+ /** Hit rate as a percentage (0-100), rounded to two decimal places. */
23
+ hitRate: number;
24
+ }
25
+ /**
26
+ * Configuration options for constructing an {@link LRUCache} instance.
27
+ *
28
+ * @remarks
29
+ * All fields are optional and have sensible defaults: 1000 entries max
30
+ * and a 24-hour TTL.
31
+ */
32
+ export interface LRUCacheOptions {
33
+ /** Maximum number of entries before the least-recently-used entry is evicted (default: 1000). */
34
+ maxSize?: number;
35
+ /** Default time-to-live in milliseconds for new entries (default: 24 hours). */
36
+ ttl?: number;
37
+ }
38
+ /**
39
+ * Generic least-recently-used (LRU) cache with time-to-live support.
40
+ *
41
+ * @remarks
42
+ * Backed by a `Map` whose insertion order doubles as the LRU eviction
43
+ * order. Expired entries are lazily evicted on access. The cache tracks
44
+ * hit/miss statistics for observability.
45
+ *
46
+ * @typeParam T - The type of cached values.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const cache = new LRUCache<string>({ maxSize: 100, ttl: 60_000 });
51
+ * cache.set('key', 'value');
52
+ * cache.get('key'); // "value"
53
+ * ```
54
+ */
55
+ export declare class LRUCache<T> {
56
+ /** Internal map storing cache entries in insertion (LRU) order. */
57
+ private cache;
58
+ /** Maximum number of entries before eviction. */
59
+ private maxSize;
60
+ /** Default time-to-live in milliseconds for new entries. */
61
+ private defaultTtl;
62
+ /** Running hit/miss counters for observability. */
63
+ private stats;
64
+ /**
65
+ * Create a new LRU cache.
66
+ *
67
+ * @remarks
68
+ * When no options are provided the cache defaults to 1000 entries max
69
+ * and a 24-hour TTL.
70
+ *
71
+ * @param options - Optional configuration for max size and TTL.
72
+ */
73
+ constructor(options?: LRUCacheOptions);
74
+ /**
75
+ * Retrieve a cached value by key.
76
+ *
77
+ * @remarks
78
+ * Returns `undefined` and increments the miss counter when the key is
79
+ * absent or its entry has expired. On a hit the entry is promoted to
80
+ * most-recently-used position.
81
+ *
82
+ * @param key - The cache key to look up.
83
+ * @returns The cached value, or `undefined` on miss or expiration.
84
+ */
85
+ get(key: string): T | undefined;
86
+ /**
87
+ * Insert or update a cache entry.
88
+ *
89
+ * @remarks
90
+ * If the cache is at capacity, the least-recently-used entry is evicted
91
+ * before the new entry is inserted. An existing entry with the same key
92
+ * is replaced (and its TTL is reset).
93
+ *
94
+ * @param key - The cache key.
95
+ * @param value - The value to cache.
96
+ * @param ttl - Optional per-entry TTL in milliseconds (overrides default).
97
+ */
98
+ set(key: string, value: T, ttl?: number): void;
99
+ /**
100
+ * Remove a single entry from the cache by key.
101
+ *
102
+ * @remarks
103
+ * No-op if the key does not exist. Does not affect hit/miss statistics.
104
+ *
105
+ * @param key - The cache key to remove.
106
+ */
107
+ delete(key: string): void;
108
+ /**
109
+ * Remove all entries from the cache and reset hit/miss statistics.
110
+ *
111
+ * @remarks
112
+ * After calling `clear()`, both the entry map and the hit/miss counters
113
+ * are zeroed, returning the cache to its initial state.
114
+ */
115
+ clear(): void;
116
+ /**
117
+ * Return the number of live (non-expired) entries in the cache.
118
+ *
119
+ * @remarks
120
+ * Performs a lazy sweep to remove expired entries before counting.
121
+ *
122
+ * @returns The current number of live entries.
123
+ */
124
+ size(): number;
125
+ /**
126
+ * Check whether a non-expired entry exists for the given key.
127
+ *
128
+ * @remarks
129
+ * Expired entries are lazily evicted during this check. This method does
130
+ * not promote the entry to most-recently-used position.
131
+ *
132
+ * @param key - The cache key to check.
133
+ * @returns `true` if a live entry exists, `false` otherwise.
134
+ */
135
+ has(key: string): boolean;
136
+ /**
137
+ * Retrieve a snapshot of cache performance statistics.
138
+ *
139
+ * @remarks
140
+ * Triggers a lazy sweep of expired entries (via {@link LRUCache.size})
141
+ * so that the reported `size` reflects only live entries.
142
+ *
143
+ * @returns A {@link CacheStats} object with hits, misses, size, and hit rate.
144
+ */
145
+ getStats(): CacheStats;
146
+ /**
147
+ * Reset the hit/miss counters to zero without clearing cached entries.
148
+ *
149
+ * @remarks
150
+ * Useful for measuring hit rate over a specific time window without
151
+ * evicting any cached data.
152
+ */
153
+ resetStats(): void;
154
+ }
155
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,QAAQ,CAAC,CAAC;IACrB,mEAAmE;IACnE,OAAO,CAAC,KAAK,CAA6B;IAC1C,iDAAiD;IACjD,OAAO,CAAC,OAAO,CAAS;IACxB,4DAA4D;IAC5D,OAAO,CAAC,UAAU,CAAS;IAC3B,mDAAmD;IACnD,OAAO,CAAC,KAAK,CAAmC;IAEhD;;;;;;;;OAQG;gBACS,OAAO,GAAE,eAAoB;IAOzC;;;;;;;;;;OAUG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAsB/B;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAmB9C;;;;;;;OAOG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB;;;;;;OAMG;IACH,KAAK,IAAI,IAAI;IAMb;;;;;;;OAOG;IACH,IAAI,IAAI,MAAM;IAUd;;;;;;;;;OASG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUzB;;;;;;;;OAQG;IACH,QAAQ,IAAI,UAAU;IAWtB;;;;;;OAMG;IACH,UAAU,IAAI,IAAI;CAInB"}
package/dist/cache.js ADDED
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Generic LRU cache with TTL support and hit/miss statistics.
3
+ *
4
+ * Provider-agnostic — no framework dependencies.
5
+ */
6
+ /**
7
+ * Generic least-recently-used (LRU) cache with time-to-live support.
8
+ *
9
+ * @remarks
10
+ * Backed by a `Map` whose insertion order doubles as the LRU eviction
11
+ * order. Expired entries are lazily evicted on access. The cache tracks
12
+ * hit/miss statistics for observability.
13
+ *
14
+ * @typeParam T - The type of cached values.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const cache = new LRUCache<string>({ maxSize: 100, ttl: 60_000 });
19
+ * cache.set('key', 'value');
20
+ * cache.get('key'); // "value"
21
+ * ```
22
+ */
23
+ export class LRUCache {
24
+ /** Internal map storing cache entries in insertion (LRU) order. */
25
+ cache;
26
+ /** Maximum number of entries before eviction. */
27
+ maxSize;
28
+ /** Default time-to-live in milliseconds for new entries. */
29
+ defaultTtl;
30
+ /** Running hit/miss counters for observability. */
31
+ stats;
32
+ /**
33
+ * Create a new LRU cache.
34
+ *
35
+ * @remarks
36
+ * When no options are provided the cache defaults to 1000 entries max
37
+ * and a 24-hour TTL.
38
+ *
39
+ * @param options - Optional configuration for max size and TTL.
40
+ */
41
+ constructor(options = {}) {
42
+ this.cache = new Map();
43
+ this.maxSize = options.maxSize ?? 1000;
44
+ this.defaultTtl = options.ttl ?? 24 * 60 * 60 * 1000;
45
+ this.stats = { hits: 0, misses: 0 };
46
+ }
47
+ /**
48
+ * Retrieve a cached value by key.
49
+ *
50
+ * @remarks
51
+ * Returns `undefined` and increments the miss counter when the key is
52
+ * absent or its entry has expired. On a hit the entry is promoted to
53
+ * most-recently-used position.
54
+ *
55
+ * @param key - The cache key to look up.
56
+ * @returns The cached value, or `undefined` on miss or expiration.
57
+ */
58
+ get(key) {
59
+ const entry = this.cache.get(key);
60
+ if (!entry) {
61
+ this.stats.misses++;
62
+ return undefined;
63
+ }
64
+ if (Date.now() > entry.expiresAt) {
65
+ this.cache.delete(key);
66
+ this.stats.misses++;
67
+ return undefined;
68
+ }
69
+ // Move to end (most recently used)
70
+ this.cache.delete(key);
71
+ this.cache.set(key, entry);
72
+ this.stats.hits++;
73
+ return entry.value;
74
+ }
75
+ /**
76
+ * Insert or update a cache entry.
77
+ *
78
+ * @remarks
79
+ * If the cache is at capacity, the least-recently-used entry is evicted
80
+ * before the new entry is inserted. An existing entry with the same key
81
+ * is replaced (and its TTL is reset).
82
+ *
83
+ * @param key - The cache key.
84
+ * @param value - The value to cache.
85
+ * @param ttl - Optional per-entry TTL in milliseconds (overrides default).
86
+ */
87
+ set(key, value, ttl) {
88
+ const effectiveTtl = ttl ?? this.defaultTtl;
89
+ const entry = {
90
+ value,
91
+ expiresAt: Date.now() + effectiveTtl,
92
+ };
93
+ this.cache.delete(key);
94
+ if (this.cache.size >= this.maxSize) {
95
+ const firstKey = this.cache.keys().next().value;
96
+ if (firstKey !== undefined) {
97
+ this.cache.delete(firstKey);
98
+ }
99
+ }
100
+ this.cache.set(key, entry);
101
+ }
102
+ /**
103
+ * Remove a single entry from the cache by key.
104
+ *
105
+ * @remarks
106
+ * No-op if the key does not exist. Does not affect hit/miss statistics.
107
+ *
108
+ * @param key - The cache key to remove.
109
+ */
110
+ delete(key) {
111
+ this.cache.delete(key);
112
+ }
113
+ /**
114
+ * Remove all entries from the cache and reset hit/miss statistics.
115
+ *
116
+ * @remarks
117
+ * After calling `clear()`, both the entry map and the hit/miss counters
118
+ * are zeroed, returning the cache to its initial state.
119
+ */
120
+ clear() {
121
+ this.cache.clear();
122
+ this.stats.hits = 0;
123
+ this.stats.misses = 0;
124
+ }
125
+ /**
126
+ * Return the number of live (non-expired) entries in the cache.
127
+ *
128
+ * @remarks
129
+ * Performs a lazy sweep to remove expired entries before counting.
130
+ *
131
+ * @returns The current number of live entries.
132
+ */
133
+ size() {
134
+ const now = Date.now();
135
+ for (const [key, entry] of this.cache.entries()) {
136
+ if (now > entry.expiresAt) {
137
+ this.cache.delete(key);
138
+ }
139
+ }
140
+ return this.cache.size;
141
+ }
142
+ /**
143
+ * Check whether a non-expired entry exists for the given key.
144
+ *
145
+ * @remarks
146
+ * Expired entries are lazily evicted during this check. This method does
147
+ * not promote the entry to most-recently-used position.
148
+ *
149
+ * @param key - The cache key to check.
150
+ * @returns `true` if a live entry exists, `false` otherwise.
151
+ */
152
+ has(key) {
153
+ const entry = this.cache.get(key);
154
+ if (!entry)
155
+ return false;
156
+ if (Date.now() > entry.expiresAt) {
157
+ this.cache.delete(key);
158
+ return false;
159
+ }
160
+ return true;
161
+ }
162
+ /**
163
+ * Retrieve a snapshot of cache performance statistics.
164
+ *
165
+ * @remarks
166
+ * Triggers a lazy sweep of expired entries (via {@link LRUCache.size})
167
+ * so that the reported `size` reflects only live entries.
168
+ *
169
+ * @returns A {@link CacheStats} object with hits, misses, size, and hit rate.
170
+ */
171
+ getStats() {
172
+ const total = this.stats.hits + this.stats.misses;
173
+ return {
174
+ hits: this.stats.hits,
175
+ misses: this.stats.misses,
176
+ size: this.size(),
177
+ maxSize: this.maxSize,
178
+ hitRate: total > 0 ? parseFloat(((this.stats.hits / total) * 100).toFixed(2)) : 0,
179
+ };
180
+ }
181
+ /**
182
+ * Reset the hit/miss counters to zero without clearing cached entries.
183
+ *
184
+ * @remarks
185
+ * Useful for measuring hit rate over a specific time window without
186
+ * evicting any cached data.
187
+ */
188
+ resetStats() {
189
+ this.stats.hits = 0;
190
+ this.stats.misses = 0;
191
+ }
192
+ }
193
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Lightweight llmtxt client for agents.
3
+ * Wraps the ClawMsgr attachment API with typed helpers.
4
+ * No framework dependencies — uses native fetch.
5
+ *
6
+ * When `@cleocode/lafs` is installed, responses are validated
7
+ * against the LAFS envelope schema. Without it, raw JSON is parsed directly.
8
+ */
9
+ import type { AttachmentReshareOptions, AttachmentSharingMode, AttachmentVersionOptions } from './types.js';
10
+ export interface LlmtxtClientConfig {
11
+ apiBase: string;
12
+ apiKey: string;
13
+ agentId: string;
14
+ }
15
+ export interface UploadResult {
16
+ slug: string;
17
+ contentHash: string;
18
+ originalSize: number;
19
+ compressedSize: number;
20
+ compressionRatio: number;
21
+ tokens: number;
22
+ signedUrl: string;
23
+ expiresAt: number;
24
+ }
25
+ export interface FetchResult {
26
+ slug: string;
27
+ content: string;
28
+ format: string;
29
+ title?: string;
30
+ contentHash: string;
31
+ originalSize: number;
32
+ tokens: number;
33
+ }
34
+ export interface ReshareResult {
35
+ slug: string;
36
+ mode: AttachmentSharingMode;
37
+ signedUrl?: string;
38
+ expiresAt?: number | null;
39
+ }
40
+ /** Backward-compatible alias. Prefer `ReshareResult`. */
41
+ export type ResignResult = ReshareResult;
42
+ export interface AttachmentVersionResult {
43
+ slug: string;
44
+ versionNumber: number;
45
+ patchText?: string;
46
+ contentHash?: string;
47
+ createdAt?: string;
48
+ createdBy?: string;
49
+ changelog?: string;
50
+ }
51
+ export declare function createClient(config: LlmtxtClientConfig): {
52
+ /** Upload content as an attachment to a conversation. */
53
+ upload(conversationId: string, content: string, options?: {
54
+ format?: string;
55
+ title?: string;
56
+ expiresIn?: number;
57
+ }): Promise<UploadResult>;
58
+ /** Fetch content from a signed URL. */
59
+ fetch(signedUrl: string): Promise<FetchResult>;
60
+ /** Fetch an attachment shared in a conversation without needing a signed URL. */
61
+ fetchFromConversation(slug: string, conversationId: string): Promise<FetchResult>;
62
+ /** Fetch an attachment owned by the current agent. */
63
+ fetchOwned(slug: string): Promise<FetchResult>;
64
+ /**
65
+ * Change how an attachment is shared. For `signed_url` mode the API may
66
+ * return a fresh `signedUrl`; for `conversation`/`public` it may not.
67
+ */
68
+ reshare(slug: string, options?: AttachmentReshareOptions): Promise<ReshareResult>;
69
+ /** Backward-compatible alias for older API wording. Prefer `reshare`. */
70
+ resign(slug: string, options?: AttachmentReshareOptions): Promise<ResignResult>;
71
+ /** Build a version patch locally using the Rust/WASM core. */
72
+ createVersionPatch(original: string, updated: string): string;
73
+ /** Submit a patch as the next version for an attachment slug. */
74
+ addVersion(slug: string, patchText: string, options?: AttachmentVersionOptions): Promise<AttachmentVersionResult>;
75
+ /** Convenience helper that diffs local content then appends the new version. */
76
+ addVersionFromContent(slug: string, original: string, updated: string, options?: AttachmentVersionOptions): Promise<AttachmentVersionResult>;
77
+ /** Check if a signed URL is still valid without fetching content. */
78
+ isValid(signedUrl: string): boolean;
79
+ };
80
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,qBAAqB,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC;AAEzC,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0CD,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB;IAQnD,yDAAyD;2BAEvC,MAAM,WACb,MAAM,YACN;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/D,OAAO,CAAC,YAAY,CAAC;IAWxB,uCAAuC;qBAChB,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAMpD,iFAAiF;gCAC/C,MAAM,kBAAkB,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAUvF,sDAAsD;qBAC/B,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAMpD;;;OAGG;kBAEK,MAAM,YACH,wBAAwB,GAChC,OAAO,CAAC,aAAa,CAAC;IAWzB,yEAAyE;iBAEjE,MAAM,YACH,wBAAwB,GAChC,OAAO,CAAC,YAAY,CAAC;IAIxB,8DAA8D;iCACjC,MAAM,WAAW,MAAM,GAAG,MAAM;IAI7D,iEAAiE;qBAEzD,MAAM,aACD,MAAM,YACR,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC;IAUnC,gFAAgF;gCAExE,MAAM,YACF,MAAM,WACP,MAAM,YACN,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC;IAKnC,qEAAqE;uBAClD,MAAM,GAAG,OAAO;EAWtC"}