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
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Storage content reference types.
3
+ *
4
+ * Abstracts where document content lives -- inline in a database column
5
+ * or in an external object store (S3-compatible). Platform implementations
6
+ * provide the actual storage backend; llmtxt defines the portable types.
7
+ */
8
+ /** How document content is stored. */
9
+ export type StorageType = 'inline' | 'object-store';
10
+ /** Compression method used for stored content. */
11
+ export type CompressionMethod = 'deflate' | 'none';
12
+ /**
13
+ * Reference to where a document's compressed content lives.
14
+ *
15
+ * Inline: content is stored directly in the database (small documents).
16
+ * Object-store: content is stored in S3-compatible storage, referenced by key.
17
+ */
18
+ export interface ContentRef {
19
+ /** Storage backend type. */
20
+ type: StorageType;
21
+ /**
22
+ * Location of the content.
23
+ * - For `inline`: not used (content is in the database row).
24
+ * - For `object-store`: the object key (e.g. `attachments/xK9mP2nQ/v3.zlib`).
25
+ */
26
+ storageKey?: string;
27
+ /** SHA-256 hash of the uncompressed content for integrity verification. */
28
+ contentHash: string;
29
+ /** Size of the uncompressed content in bytes. */
30
+ originalSize: number;
31
+ /** Size of the compressed content in bytes. */
32
+ compressedSize: number;
33
+ /** Compression method used. */
34
+ compression: CompressionMethod;
35
+ }
36
+ /** Metadata about a stored document blob. */
37
+ export interface StorageMetadata {
38
+ /** Content reference. */
39
+ ref: ContentRef;
40
+ /** When the content was first stored (ms since epoch). */
41
+ createdAt: number;
42
+ /** When the content was last accessed (ms since epoch). */
43
+ lastAccessedAt: number;
44
+ /** Number of times the content has been accessed. */
45
+ accessCount: number;
46
+ }
47
+ /**
48
+ * Create a content reference for inline storage.
49
+ *
50
+ * @param contentHash - SHA-256 hash of the uncompressed content.
51
+ * @param originalSize - Size of the uncompressed content in bytes.
52
+ * @param compressedSize - Size of the compressed content in bytes.
53
+ * @returns An inline content reference.
54
+ */
55
+ export declare function inlineRef(contentHash: string, originalSize: number, compressedSize: number): ContentRef;
56
+ /**
57
+ * Create a content reference for object-store storage.
58
+ *
59
+ * @param storageKey - The object key in the store.
60
+ * @param contentHash - SHA-256 hash of the uncompressed content.
61
+ * @param originalSize - Size of the uncompressed content in bytes.
62
+ * @param compressedSize - Size of the compressed content in bytes.
63
+ * @returns An object-store content reference.
64
+ */
65
+ export declare function objectStoreRef(storageKey: string, contentHash: string, originalSize: number, compressedSize: number): ContentRef;
66
+ /**
67
+ * Generate a storage key for a document version.
68
+ *
69
+ * Convention: `attachments/{slug}/v{version}.zlib`
70
+ *
71
+ * @param slug - Document slug.
72
+ * @param version - Version number.
73
+ * @returns The object storage key.
74
+ */
75
+ export declare function versionStorageKey(slug: string, version: number): string;
76
+ /**
77
+ * Determine whether content should be stored in object-store vs inline.
78
+ *
79
+ * Threshold: content larger than 64KB compressed goes to object-store.
80
+ *
81
+ * @param compressedSize - Size of the compressed content in bytes.
82
+ * @param threshold - Size threshold in bytes. Defaults to 65536 (64KB).
83
+ * @returns `true` if the content should use object-store.
84
+ */
85
+ export declare function shouldUseObjectStore(compressedSize: number, threshold?: number): boolean;
86
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/sdk/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,sCAAsC;AACtC,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEpD,kDAAkD;AAClD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,WAAW,EAAE,iBAAiB,CAAC;CAChC;AAID,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,GAAG,EAAE,UAAU,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,cAAc,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;CACrB;AAID;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,UAAU,CAQZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,UAAU,CASZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,OAAO,CAEvF"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Storage content reference types.
3
+ *
4
+ * Abstracts where document content lives -- inline in a database column
5
+ * or in an external object store (S3-compatible). Platform implementations
6
+ * provide the actual storage backend; llmtxt defines the portable types.
7
+ */
8
+ // ── Helpers ────────────────────────────────────────────────────
9
+ /**
10
+ * Create a content reference for inline storage.
11
+ *
12
+ * @param contentHash - SHA-256 hash of the uncompressed content.
13
+ * @param originalSize - Size of the uncompressed content in bytes.
14
+ * @param compressedSize - Size of the compressed content in bytes.
15
+ * @returns An inline content reference.
16
+ */
17
+ export function inlineRef(contentHash, originalSize, compressedSize) {
18
+ return {
19
+ type: 'inline',
20
+ contentHash,
21
+ originalSize,
22
+ compressedSize,
23
+ compression: 'deflate',
24
+ };
25
+ }
26
+ /**
27
+ * Create a content reference for object-store storage.
28
+ *
29
+ * @param storageKey - The object key in the store.
30
+ * @param contentHash - SHA-256 hash of the uncompressed content.
31
+ * @param originalSize - Size of the uncompressed content in bytes.
32
+ * @param compressedSize - Size of the compressed content in bytes.
33
+ * @returns An object-store content reference.
34
+ */
35
+ export function objectStoreRef(storageKey, contentHash, originalSize, compressedSize) {
36
+ return {
37
+ type: 'object-store',
38
+ storageKey,
39
+ contentHash,
40
+ originalSize,
41
+ compressedSize,
42
+ compression: 'deflate',
43
+ };
44
+ }
45
+ /**
46
+ * Generate a storage key for a document version.
47
+ *
48
+ * Convention: `attachments/{slug}/v{version}.zlib`
49
+ *
50
+ * @param slug - Document slug.
51
+ * @param version - Version number.
52
+ * @returns The object storage key.
53
+ */
54
+ export function versionStorageKey(slug, version) {
55
+ return `attachments/${slug}/v${version}.zlib`;
56
+ }
57
+ /**
58
+ * Determine whether content should be stored in object-store vs inline.
59
+ *
60
+ * Threshold: content larger than 64KB compressed goes to object-store.
61
+ *
62
+ * @param compressedSize - Size of the compressed content in bytes.
63
+ * @param threshold - Size threshold in bytes. Defaults to 65536 (64KB).
64
+ * @returns `true` if the content should use object-store.
65
+ */
66
+ export function shouldUseObjectStore(compressedSize, threshold = 65536) {
67
+ return compressedSize > threshold;
68
+ }
69
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/sdk/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiDH,kEAAkE;AAElE;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACvB,WAAmB,EACnB,YAAoB,EACpB,cAAsB;IAEtB,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,WAAW;QACX,YAAY;QACZ,cAAc;QACd,WAAW,EAAE,SAAS;KACvB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,UAAkB,EAClB,WAAmB,EACnB,YAAoB,EACpB,cAAsB;IAEtB,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,UAAU;QACV,WAAW;QACX,YAAY;QACZ,cAAc;QACd,WAAW,EAAE,SAAS;KACvB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,OAAe;IAC7D,OAAO,eAAe,IAAI,KAAK,OAAO,OAAO,CAAC;AAChD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,cAAsB,EAAE,SAAS,GAAG,KAAK;IAC5E,OAAO,cAAc,GAAG,SAAS,CAAC;AACpC,CAAC"}
@@ -0,0 +1,107 @@
1
+ /** A single version entry in a document's patch stack. */
2
+ export interface VersionEntry {
3
+ /** Sequential version number (1-based). */
4
+ versionNumber: number;
5
+ /** Unified diff patch text. */
6
+ patchText: string;
7
+ /** Agent that authored this version. */
8
+ createdBy: string;
9
+ /** One-line description of the change. */
10
+ changelog: string;
11
+ /** SHA-256 hash of the resulting content after applying this patch. */
12
+ contentHash: string;
13
+ /** Timestamp of creation (ms since epoch). */
14
+ createdAt: number;
15
+ }
16
+ /** Result of reconstructing a document at a specific version. */
17
+ export interface ReconstructionResult {
18
+ /** The document content at the requested version. */
19
+ content: string;
20
+ /** The version number that was reconstructed. */
21
+ version: number;
22
+ /** Number of patches applied to reach this version. */
23
+ patchesApplied: number;
24
+ /** SHA-256 hash of the reconstructed content. */
25
+ contentHash: string;
26
+ /** Token count of the reconstructed content. */
27
+ tokenCount: number;
28
+ }
29
+ /** Result of validating whether a patch applies cleanly. */
30
+ export interface PatchValidationResult {
31
+ /** Whether the patch can be applied without conflicts. */
32
+ applies: boolean;
33
+ /** Error message if the patch does not apply. */
34
+ error?: string;
35
+ /** The content that would result if the patch applies. */
36
+ resultContent?: string;
37
+ }
38
+ /**
39
+ * Reconstruct a document at a specific version by applying patches
40
+ * sequentially from the base content.
41
+ *
42
+ * @param baseContent - The original document content (version 0).
43
+ * @param patches - Ordered array of version entries.
44
+ * @param targetVersion - The version to reconstruct. Defaults to latest.
45
+ * @returns The reconstructed document content and metadata.
46
+ * @throws If a patch in the sequence fails to apply.
47
+ */
48
+ export declare function reconstructVersion(baseContent: string, patches: VersionEntry[], targetVersion?: number): ReconstructionResult;
49
+ /**
50
+ * Check whether a patch applies cleanly to the given content.
51
+ *
52
+ * @param content - The current document content.
53
+ * @param patchText - The unified diff to test.
54
+ * @returns Whether the patch applies and the resulting content.
55
+ */
56
+ export declare function validatePatchApplies(content: string, patchText: string): PatchValidationResult;
57
+ /**
58
+ * Squash a sequence of patches into a single unified diff.
59
+ *
60
+ * Applies all patches sequentially to the base content, then produces
61
+ * one diff from base to final state.
62
+ *
63
+ * @param baseContent - The content before the first patch.
64
+ * @param patches - Ordered array of version entries to squash.
65
+ * @returns A single patch text and the final content hash.
66
+ */
67
+ export declare function squashPatches(baseContent: string, patches: VersionEntry[]): {
68
+ patchText: string;
69
+ contentHash: string;
70
+ tokenCount: number;
71
+ };
72
+ /**
73
+ * Compute a reverse patch that undoes a version's changes.
74
+ *
75
+ * @param contentBefore - Document content before the patch was applied.
76
+ * @param contentAfter - Document content after the patch was applied.
77
+ * @returns A unified diff that reverts `contentAfter` back to `contentBefore`.
78
+ */
79
+ export declare function computeReversePatch(contentBefore: string, contentAfter: string): string;
80
+ /** Summary of changes between two versions. */
81
+ export interface VersionDiffSummary {
82
+ /** Source version number. */
83
+ fromVersion: number;
84
+ /** Target version number. */
85
+ toVersion: number;
86
+ /** Lines added between versions. */
87
+ addedLines: number;
88
+ /** Lines removed between versions. */
89
+ removedLines: number;
90
+ /** Tokens added between versions. */
91
+ addedTokens: number;
92
+ /** Tokens removed between versions. */
93
+ removedTokens: number;
94
+ /** Unified diff text. */
95
+ patchText: string;
96
+ }
97
+ /**
98
+ * Compute a diff summary between two versions of a document.
99
+ *
100
+ * @param baseContent - The original document content (version 0).
101
+ * @param patches - Full ordered patch stack.
102
+ * @param fromVersion - Start version.
103
+ * @param toVersion - End version.
104
+ * @returns Diff statistics and patch text between the two versions.
105
+ */
106
+ export declare function diffVersions(baseContent: string, patches: VersionEntry[], fromVersion: number, toVersion: number): VersionDiffSummary;
107
+ //# sourceMappingURL=versions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/sdk/versions.ts"],"names":[],"mappings":"AAYA,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4DAA4D;AAC5D,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,CAAC,EAAE,MAAM,GACrB,oBAAoB,CA4BtB;AAID;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,qBAAqB,CAavB;AAID;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EAAE,GACtB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAchE;AAID;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,MAAM,CAER;AAID,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,kBAAkB,CAepB"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Version stack management for collaborative documents.
3
+ *
4
+ * Provides helpers to reconstruct any version from a base document
5
+ * plus a sequence of patches, validate patch applicability, squash
6
+ * consecutive patches, and compute reverse patches for rollback.
7
+ */
8
+ import { createPatch, applyPatch, reconstructVersion as wasmReconstruct, squashPatchesWasm } from '../patch.js';
9
+ import { calculateTokens, hashContent, computeDiff } from '../compression.js';
10
+ // ── Reconstruction ─────────────────────────────────────────────
11
+ /**
12
+ * Reconstruct a document at a specific version by applying patches
13
+ * sequentially from the base content.
14
+ *
15
+ * @param baseContent - The original document content (version 0).
16
+ * @param patches - Ordered array of version entries.
17
+ * @param targetVersion - The version to reconstruct. Defaults to latest.
18
+ * @returns The reconstructed document content and metadata.
19
+ * @throws If a patch in the sequence fails to apply.
20
+ */
21
+ export function reconstructVersion(baseContent, patches, targetVersion) {
22
+ const sorted = [...patches].sort((a, b) => a.versionNumber - b.versionNumber);
23
+ const target = targetVersion ?? (sorted.length > 0 ? sorted[sorted.length - 1].versionNumber : 0);
24
+ if (target === 0) {
25
+ return {
26
+ content: baseContent,
27
+ version: 0,
28
+ patchesApplied: 0,
29
+ contentHash: hashContent(baseContent),
30
+ tokenCount: calculateTokens(baseContent),
31
+ };
32
+ }
33
+ // Delegate to Rust for N patch applications in a single WASM call
34
+ const patchTexts = sorted
35
+ .filter(e => e.versionNumber <= target)
36
+ .map(e => e.patchText);
37
+ const patchesJson = JSON.stringify(patchTexts);
38
+ const content = wasmReconstruct(baseContent, patchesJson, patchTexts.length);
39
+ return {
40
+ content,
41
+ version: target,
42
+ patchesApplied: patchTexts.length,
43
+ contentHash: hashContent(content),
44
+ tokenCount: calculateTokens(content),
45
+ };
46
+ }
47
+ // ── Validation ─────────────────────────────────────────────────
48
+ /**
49
+ * Check whether a patch applies cleanly to the given content.
50
+ *
51
+ * @param content - The current document content.
52
+ * @param patchText - The unified diff to test.
53
+ * @returns Whether the patch applies and the resulting content.
54
+ */
55
+ export function validatePatchApplies(content, patchText) {
56
+ try {
57
+ const result = applyPatch(content, patchText);
58
+ if (result === content && patchText.trim().length > 0) {
59
+ return { applies: false, error: 'Patch did not modify content (possible conflict)' };
60
+ }
61
+ return { applies: true, resultContent: result };
62
+ }
63
+ catch (err) {
64
+ return {
65
+ applies: false,
66
+ error: err instanceof Error ? err.message : String(err),
67
+ };
68
+ }
69
+ }
70
+ // ── Squashing ──────────────────────────────────────────────────
71
+ /**
72
+ * Squash a sequence of patches into a single unified diff.
73
+ *
74
+ * Applies all patches sequentially to the base content, then produces
75
+ * one diff from base to final state.
76
+ *
77
+ * @param baseContent - The content before the first patch.
78
+ * @param patches - Ordered array of version entries to squash.
79
+ * @returns A single patch text and the final content hash.
80
+ */
81
+ export function squashPatches(baseContent, patches) {
82
+ const sorted = [...patches].sort((a, b) => a.versionNumber - b.versionNumber);
83
+ const patchesJson = JSON.stringify(sorted.map(e => e.patchText));
84
+ // Single WASM call: apply all patches then diff base vs final
85
+ const patchText = squashPatchesWasm(baseContent, patchesJson);
86
+ // Reconstruct final content to compute hash and tokens
87
+ const finalContent = wasmReconstruct(baseContent, patchesJson, sorted.length);
88
+ return {
89
+ patchText,
90
+ contentHash: hashContent(finalContent),
91
+ tokenCount: calculateTokens(finalContent),
92
+ };
93
+ }
94
+ // ── Reverse Patch ──────────────────────────────────────────────
95
+ /**
96
+ * Compute a reverse patch that undoes a version's changes.
97
+ *
98
+ * @param contentBefore - Document content before the patch was applied.
99
+ * @param contentAfter - Document content after the patch was applied.
100
+ * @returns A unified diff that reverts `contentAfter` back to `contentBefore`.
101
+ */
102
+ export function computeReversePatch(contentBefore, contentAfter) {
103
+ return createPatch(contentAfter, contentBefore);
104
+ }
105
+ /**
106
+ * Compute a diff summary between two versions of a document.
107
+ *
108
+ * @param baseContent - The original document content (version 0).
109
+ * @param patches - Full ordered patch stack.
110
+ * @param fromVersion - Start version.
111
+ * @param toVersion - End version.
112
+ * @returns Diff statistics and patch text between the two versions.
113
+ */
114
+ export function diffVersions(baseContent, patches, fromVersion, toVersion) {
115
+ const fromContent = reconstructVersion(baseContent, patches, fromVersion).content;
116
+ const toContent = reconstructVersion(baseContent, patches, toVersion).content;
117
+ const diff = computeDiff(fromContent, toContent);
118
+ const patchText = createPatch(fromContent, toContent);
119
+ return {
120
+ fromVersion,
121
+ toVersion,
122
+ addedLines: diff.addedLines,
123
+ removedLines: diff.removedLines,
124
+ addedTokens: diff.addedTokens,
125
+ removedTokens: diff.removedTokens,
126
+ patchText,
127
+ };
128
+ }
129
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/sdk/versions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Parameters that uniquely identify a signed URL access grant.
3
+ */
4
+ export interface SignedUrlParams {
5
+ slug: string;
6
+ agentId: string;
7
+ conversationId: string;
8
+ expiresAt: number;
9
+ }
10
+ /**
11
+ * Configuration for generating and verifying signed URLs.
12
+ */
13
+ export interface SignedUrlConfig {
14
+ secret: string;
15
+ baseUrl: string;
16
+ /** Optional path prefix like `/attachments`. Default: root path. */
17
+ pathPrefix?: string;
18
+ /** Signature length in hex chars. Default: 16. */
19
+ signatureLength?: number;
20
+ }
21
+ /**
22
+ * Outcome of verifying a signed URL.
23
+ */
24
+ export interface VerifyResult {
25
+ valid: boolean;
26
+ reason?: 'missing_params' | 'expired' | 'invalid_signature';
27
+ params?: SignedUrlParams;
28
+ }
29
+ /**
30
+ * Compute the HMAC-SHA256 signature for signed URL parameters.
31
+ * Delegates to the Rust WASM module.
32
+ */
33
+ export declare function computeSignature(params: SignedUrlParams, secret: string): string;
34
+ /**
35
+ * Compute signature with configurable length.
36
+ * Use 16 for short-lived URLs (default), 32 for long-lived URLs (128 bits).
37
+ */
38
+ export declare function computeSignatureWithLength(params: SignedUrlParams, secret: string, sigLength: number): string;
39
+ /**
40
+ * Generate a signed URL for accessing a document.
41
+ */
42
+ export declare function generateSignedUrl(params: SignedUrlParams, config: SignedUrlConfig): string;
43
+ /**
44
+ * Verify a signed URL's signature and expiration.
45
+ * Uses timing-safe comparison to prevent timing attacks.
46
+ */
47
+ export declare function verifySignedUrl(url: string | URL, secret: string): VerifyResult;
48
+ /**
49
+ * Parameters for org-scoped signed URLs (Phase 5 enterprise).
50
+ * Extends conversation-scoped params with an organization ID.
51
+ */
52
+ export interface OrgSignedUrlParams extends SignedUrlParams {
53
+ orgId: string;
54
+ }
55
+ /**
56
+ * Compute the HMAC-SHA256 signature for org-scoped signed URL parameters.
57
+ * Includes orgId in the HMAC payload for organization-level access control.
58
+ * Returns 32 hex characters (128 bits) by default.
59
+ */
60
+ export declare function computeOrgSignature(params: OrgSignedUrlParams, secret: string): string;
61
+ /**
62
+ * Compute org-scoped signature with configurable length.
63
+ */
64
+ export declare function computeOrgSignatureWithLength(params: OrgSignedUrlParams, secret: string, sigLength: number): string;
65
+ /**
66
+ * Generate an org-scoped signed URL for accessing a document.
67
+ * The URL includes the org parameter for organization-level access verification.
68
+ */
69
+ export declare function generateOrgSignedUrl(params: OrgSignedUrlParams, config: SignedUrlConfig): string;
70
+ /**
71
+ * Verify an org-scoped signed URL's signature and expiration.
72
+ */
73
+ export declare function verifyOrgSignedUrl(url: string | URL, secret: string): VerifyResult & {
74
+ orgId?: string;
75
+ };
76
+ /**
77
+ * Generate a signed URL that expires after the given duration.
78
+ */
79
+ export declare function generateTimedUrl(params: Omit<SignedUrlParams, 'expiresAt'>, config: SignedUrlConfig, ttlMs?: number): string;
80
+ /**
81
+ * Derive a per-agent signing key from their API key.
82
+ * Delegates to the Rust WASM module.
83
+ */
84
+ export declare function deriveSigningKey(apiKey: string): string;
85
+ /**
86
+ * Check whether a timestamp has expired.
87
+ * Returns false for null/undefined (no expiration set).
88
+ */
89
+ export declare function isExpired(expiresAt: number | null | undefined): boolean;
90
+ //# sourceMappingURL=signed-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signed-url.d.ts","sourceRoot":"","sources":["../src/signed-url.ts"],"names":[],"mappings":"AAmBA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,GAAG,mBAAmB,CAAC;IAC5D,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQhF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CASR;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAS1F;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CA8B/E;AAOD;;;GAGG;AACH,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAStF;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAUhG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA8BvG;AAID;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,EAC1C,MAAM,EAAE,eAAe,EACvB,KAAK,SAAiB,GACrB,MAAM,CAKR;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvD;AAcD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGvE"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Signed URL generation and verification for conversation-scoped,
3
+ * time-limited access to llmtxt content.
4
+ *
5
+ * HMAC computation and key derivation delegate to the Rust WASM module.
6
+ * URL construction and verification logic stays in TypeScript (URL parsing
7
+ * is complex in WASM and not needed in the Rust native crate).
8
+ */
9
+ import { computeSignature as wasmComputeSignature, computeSignatureWithLength as wasmComputeSignatureWithLength, computeOrgSignature as wasmComputeOrgSignature, computeOrgSignatureWithLength as wasmComputeOrgSignatureWithLength, deriveSigningKey as wasmDeriveSigningKey, isExpired as wasmIsExpired, } from './wasm.js';
10
+ // ── Signature (WASM-backed) ─────────────────────────────────────
11
+ /**
12
+ * Compute the HMAC-SHA256 signature for signed URL parameters.
13
+ * Delegates to the Rust WASM module.
14
+ */
15
+ export function computeSignature(params, secret) {
16
+ return wasmComputeSignature(params.slug, params.agentId, params.conversationId, params.expiresAt, secret);
17
+ }
18
+ /**
19
+ * Compute signature with configurable length.
20
+ * Use 16 for short-lived URLs (default), 32 for long-lived URLs (128 bits).
21
+ */
22
+ export function computeSignatureWithLength(params, secret, sigLength) {
23
+ return wasmComputeSignatureWithLength(params.slug, params.agentId, params.conversationId, params.expiresAt, secret, sigLength);
24
+ }
25
+ // ── Generate ────────────────────────────────────────────────────
26
+ /**
27
+ * Generate a signed URL for accessing a document.
28
+ */
29
+ export function generateSignedUrl(params, config) {
30
+ const signatureLength = config.signatureLength ?? 16;
31
+ const signature = computeSignatureWithLength(params, config.secret, signatureLength);
32
+ const url = new URL(buildSignedUrlPath(params.slug, config.pathPrefix), config.baseUrl);
33
+ url.searchParams.set('agent', params.agentId);
34
+ url.searchParams.set('conv', params.conversationId);
35
+ url.searchParams.set('exp', String(params.expiresAt));
36
+ url.searchParams.set('sig', signature);
37
+ return url.toString();
38
+ }
39
+ // ── Verify ──────────────────────────────────────────────────────
40
+ /**
41
+ * Verify a signed URL's signature and expiration.
42
+ * Uses timing-safe comparison to prevent timing attacks.
43
+ */
44
+ export function verifySignedUrl(url, secret) {
45
+ const parsed = typeof url === 'string' ? new URL(url) : url;
46
+ const slug = getSignedUrlSlug(parsed);
47
+ const agent = parsed.searchParams.get('agent');
48
+ const conv = parsed.searchParams.get('conv');
49
+ const exp = parsed.searchParams.get('exp');
50
+ const sig = parsed.searchParams.get('sig');
51
+ if (!slug || !agent || !conv || !exp || !sig) {
52
+ return { valid: false, reason: 'missing_params' };
53
+ }
54
+ const expiresAt = parseInt(exp, 10);
55
+ if (isNaN(expiresAt) || isExpired(expiresAt)) {
56
+ return { valid: false, reason: 'expired' };
57
+ }
58
+ const params = { slug, agentId: agent, conversationId: conv, expiresAt };
59
+ const expected = computeSignatureWithLength(params, secret, sig.length);
60
+ // Timing-safe comparison
61
+ const sigBuf = Buffer.from(sig, 'utf-8');
62
+ const expBuf = Buffer.from(expected, 'utf-8');
63
+ if (sigBuf.length !== expBuf.length || !timingSafeEqual(sigBuf, expBuf)) {
64
+ return { valid: false, reason: 'invalid_signature' };
65
+ }
66
+ return { valid: true, params };
67
+ }
68
+ // Keep timing-safe from Node.js crypto for the URL verification step
69
+ import { timingSafeEqual } from 'node:crypto';
70
+ /**
71
+ * Compute the HMAC-SHA256 signature for org-scoped signed URL parameters.
72
+ * Includes orgId in the HMAC payload for organization-level access control.
73
+ * Returns 32 hex characters (128 bits) by default.
74
+ */
75
+ export function computeOrgSignature(params, secret) {
76
+ return wasmComputeOrgSignature(params.slug, params.agentId, params.conversationId, params.orgId, params.expiresAt, secret);
77
+ }
78
+ /**
79
+ * Compute org-scoped signature with configurable length.
80
+ */
81
+ export function computeOrgSignatureWithLength(params, secret, sigLength) {
82
+ return wasmComputeOrgSignatureWithLength(params.slug, params.agentId, params.conversationId, params.orgId, params.expiresAt, secret, sigLength);
83
+ }
84
+ /**
85
+ * Generate an org-scoped signed URL for accessing a document.
86
+ * The URL includes the org parameter for organization-level access verification.
87
+ */
88
+ export function generateOrgSignedUrl(params, config) {
89
+ const signatureLength = config.signatureLength ?? 32;
90
+ const signature = computeOrgSignatureWithLength(params, config.secret, signatureLength);
91
+ const url = new URL(buildSignedUrlPath(params.slug, config.pathPrefix), config.baseUrl);
92
+ url.searchParams.set('agent', params.agentId);
93
+ url.searchParams.set('conv', params.conversationId);
94
+ url.searchParams.set('org', params.orgId);
95
+ url.searchParams.set('exp', String(params.expiresAt));
96
+ url.searchParams.set('sig', signature);
97
+ return url.toString();
98
+ }
99
+ /**
100
+ * Verify an org-scoped signed URL's signature and expiration.
101
+ */
102
+ export function verifyOrgSignedUrl(url, secret) {
103
+ const parsed = typeof url === 'string' ? new URL(url) : url;
104
+ const slug = getSignedUrlSlug(parsed);
105
+ const agent = parsed.searchParams.get('agent');
106
+ const conv = parsed.searchParams.get('conv');
107
+ const org = parsed.searchParams.get('org');
108
+ const exp = parsed.searchParams.get('exp');
109
+ const sig = parsed.searchParams.get('sig');
110
+ if (!slug || !agent || !conv || !org || !exp || !sig) {
111
+ return { valid: false, reason: 'missing_params' };
112
+ }
113
+ const expiresAt = parseInt(exp, 10);
114
+ if (isNaN(expiresAt) || isExpired(expiresAt)) {
115
+ return { valid: false, reason: 'expired' };
116
+ }
117
+ const params = { slug, agentId: agent, conversationId: conv, orgId: org, expiresAt };
118
+ const expected = computeOrgSignatureWithLength(params, secret, sig.length);
119
+ const sigBuf = Buffer.from(sig, 'utf-8');
120
+ const expBuf = Buffer.from(expected, 'utf-8');
121
+ if (sigBuf.length !== expBuf.length || !timingSafeEqual(sigBuf, expBuf)) {
122
+ return { valid: false, reason: 'invalid_signature' };
123
+ }
124
+ return { valid: true, params, orgId: org };
125
+ }
126
+ // ── Convenience ─────────────────────────────────────────────────
127
+ /**
128
+ * Generate a signed URL that expires after the given duration.
129
+ */
130
+ export function generateTimedUrl(params, config, ttlMs = 60 * 60 * 1000) {
131
+ return generateSignedUrl({ ...params, expiresAt: Date.now() + ttlMs }, config);
132
+ }
133
+ // ── Key Derivation (WASM-backed) ────────────────────────────────
134
+ /**
135
+ * Derive a per-agent signing key from their API key.
136
+ * Delegates to the Rust WASM module.
137
+ */
138
+ export function deriveSigningKey(apiKey) {
139
+ return wasmDeriveSigningKey(apiKey);
140
+ }
141
+ function buildSignedUrlPath(slug, pathPrefix = '') {
142
+ const normalizedPrefix = pathPrefix.replace(/\/+$/, '').replace(/^([^/])/, '/$1');
143
+ return normalizedPrefix ? `${normalizedPrefix}/${slug}` : `/${slug}`;
144
+ }
145
+ function getSignedUrlSlug(url) {
146
+ const segments = url.pathname.split('/').filter(Boolean);
147
+ return segments.at(-1) ?? '';
148
+ }
149
+ // ── Expiration (WASM-backed) ────────────────────────────────────
150
+ /**
151
+ * Check whether a timestamp has expired.
152
+ * Returns false for null/undefined (no expiration set).
153
+ */
154
+ export function isExpired(expiresAt) {
155
+ if (expiresAt == null)
156
+ return false;
157
+ return wasmIsExpired(expiresAt);
158
+ }
159
+ //# sourceMappingURL=signed-url.js.map