@semiont/content 0.5.2 → 0.5.4
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/dist/checksum.d.ts +17 -0
- package/dist/checksum.d.ts.map +1 -0
- package/dist/index.d.ts +6 -178
- package/dist/index.d.ts.map +1 -0
- package/dist/mime-extensions.d.ts +33 -0
- package/dist/mime-extensions.d.ts.map +1 -0
- package/dist/representation-store.d.ts +94 -0
- package/dist/representation-store.d.ts.map +1 -0
- package/dist/working-tree-store.d.ts +128 -0
- package/dist/working-tree-store.d.ts.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checksum utilities for content verification
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate SHA-256 checksum of content
|
|
6
|
+
* @param content The content to hash
|
|
7
|
+
* @returns Hex-encoded SHA-256 hash
|
|
8
|
+
*/
|
|
9
|
+
export declare function calculateChecksum(content: string | Buffer): string;
|
|
10
|
+
/**
|
|
11
|
+
* Verify content against a checksum
|
|
12
|
+
* @param content The content to verify
|
|
13
|
+
* @param checksum The expected checksum
|
|
14
|
+
* @returns True if content matches checksum
|
|
15
|
+
*/
|
|
16
|
+
export declare function verifyChecksum(content: string | Buffer, checksum: string): boolean;
|
|
17
|
+
//# sourceMappingURL=checksum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../src/checksum.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAIlE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAElF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,181 +1,9 @@
|
|
|
1
|
-
import { SemiontProject } from '@semiont/core/node';
|
|
2
|
-
import { Logger } from '@semiont/core';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
|
-
*
|
|
2
|
+
* @semiont/content
|
|
6
3
|
*
|
|
7
|
-
*
|
|
8
|
-
* the working tree (project root) as the source of truth for file content.
|
|
9
|
-
* Resources are identified by their file:// URI, which is stable across
|
|
10
|
-
* content changes and moves (tracked by events).
|
|
11
|
-
*
|
|
12
|
-
* Two write paths:
|
|
13
|
-
* - store(content, storageUri): Write bytes to disk (API/GUI/AI path).
|
|
14
|
-
* Used when the file does not yet exist and the caller provides content.
|
|
15
|
-
* - register(storageUri, expectedChecksum?): Read an existing file and
|
|
16
|
-
* return its metadata (CLI path). The file is already on disk; we just
|
|
17
|
-
* verify and record it. If expectedChecksum is provided, throws on mismatch.
|
|
18
|
-
*
|
|
19
|
-
* Storage layout:
|
|
20
|
-
* {projectRoot}/{path-from-uri}
|
|
21
|
-
*
|
|
22
|
-
* For example, storageUri "file://docs/overview.md" resolves to
|
|
23
|
-
* {projectRoot}/docs/overview.md
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Result of store() or register()
|
|
28
|
-
*/
|
|
29
|
-
interface StoredResource {
|
|
30
|
-
storageUri: string;
|
|
31
|
-
checksum: string;
|
|
32
|
-
byteSize: number;
|
|
33
|
-
created: string;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Manages files in the project working tree
|
|
37
|
-
*/
|
|
38
|
-
declare class WorkingTreeStore {
|
|
39
|
-
private projectRoot;
|
|
40
|
-
private gitSync;
|
|
41
|
-
private logger?;
|
|
42
|
-
constructor(project: SemiontProject, logger?: Logger);
|
|
43
|
-
private shouldRunGit;
|
|
44
|
-
/**
|
|
45
|
-
* Write content to disk at the location indicated by storageUri.
|
|
46
|
-
*
|
|
47
|
-
* API/GUI/AI path: caller provides bytes; file may not yet exist.
|
|
48
|
-
*
|
|
49
|
-
* @param content - Raw bytes to write
|
|
50
|
-
* @param storageUri - file:// URI (e.g. "file://docs/overview.md")
|
|
51
|
-
* @returns Stored resource metadata
|
|
52
|
-
*/
|
|
53
|
-
store(content: Buffer, storageUri: string, options?: {
|
|
54
|
-
noGit?: boolean;
|
|
55
|
-
}): Promise<StoredResource>;
|
|
56
|
-
/**
|
|
57
|
-
* Read an existing file and return its metadata.
|
|
58
|
-
*
|
|
59
|
-
* CLI path: the file is already on disk. We read it to compute the checksum.
|
|
60
|
-
* If expectedChecksum is provided, throws ChecksumMismatchError on mismatch.
|
|
61
|
-
*
|
|
62
|
-
* @param storageUri - file:// URI (e.g. "file://docs/overview.md")
|
|
63
|
-
* @param expectedChecksum - Optional SHA-256 to verify against
|
|
64
|
-
* @returns Stored resource metadata
|
|
65
|
-
* @throws ChecksumMismatchError if expectedChecksum is provided and does not match
|
|
66
|
-
* @throws Error if file does not exist
|
|
67
|
-
*/
|
|
68
|
-
register(storageUri: string, expectedChecksum?: string, options?: {
|
|
69
|
-
noGit?: boolean;
|
|
70
|
-
}): Promise<StoredResource>;
|
|
71
|
-
/**
|
|
72
|
-
* Read file content by URI.
|
|
73
|
-
*
|
|
74
|
-
* @param storageUri - file:// URI
|
|
75
|
-
* @returns Raw bytes
|
|
76
|
-
*/
|
|
77
|
-
retrieve(storageUri: string): Promise<Buffer>;
|
|
78
|
-
/**
|
|
79
|
-
* Move a file from one URI to another.
|
|
80
|
-
*
|
|
81
|
-
* If .git/ exists in the project root and noGit is not set, runs `git mv`.
|
|
82
|
-
* Otherwise (no .git/ or noGit: true), runs fs.rename.
|
|
83
|
-
*
|
|
84
|
-
* @param fromUri - Current file:// URI
|
|
85
|
-
* @param toUri - New file:// URI
|
|
86
|
-
* @param options.noGit - Skip git mv even if .git/ is present
|
|
87
|
-
*/
|
|
88
|
-
move(fromUri: string, toUri: string, options?: {
|
|
89
|
-
noGit?: boolean;
|
|
90
|
-
}): Promise<void>;
|
|
91
|
-
/**
|
|
92
|
-
* Remove a file from the working tree.
|
|
93
|
-
*
|
|
94
|
-
* If .git/ exists and noGit is not set:
|
|
95
|
-
* - keepFile false (default): runs `git rm` (removes from index and disk)
|
|
96
|
-
* - keepFile true: runs `git rm --cached` (removes from index only, file stays on disk)
|
|
97
|
-
* If no .git/ or noGit: true:
|
|
98
|
-
* - keepFile false: runs fs.unlink
|
|
99
|
-
* - keepFile true: no-op on filesystem
|
|
100
|
-
*
|
|
101
|
-
* @param storageUri - file:// URI
|
|
102
|
-
* @param options.noGit - Skip git rm even if .git/ is present
|
|
103
|
-
* @param options.keepFile - Remove from git index only; leave file on disk
|
|
104
|
-
*/
|
|
105
|
-
remove(storageUri: string, options?: {
|
|
106
|
-
noGit?: boolean;
|
|
107
|
-
keepFile?: boolean;
|
|
108
|
-
}): Promise<void>;
|
|
109
|
-
/**
|
|
110
|
-
* Convert a file:// URI to an absolute filesystem path.
|
|
111
|
-
*
|
|
112
|
-
* "file://docs/overview.md" → "{projectRoot}/docs/overview.md"
|
|
113
|
-
*
|
|
114
|
-
* @param storageUri - file:// URI
|
|
115
|
-
* @returns Absolute path
|
|
116
|
-
*/
|
|
117
|
-
resolveUri(storageUri: string): string;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Thrown when a registered file's checksum does not match the expected value.
|
|
121
|
-
* This indicates the file on disk differs from what was recorded (e.g. modified
|
|
122
|
-
* after staging, or wrong file path provided).
|
|
123
|
-
*/
|
|
124
|
-
declare class ChecksumMismatchError extends Error {
|
|
125
|
-
readonly storageUri: string;
|
|
126
|
-
readonly expected: string;
|
|
127
|
-
readonly actual: string;
|
|
128
|
-
constructor(storageUri: string, expected: string, actual: string);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* MIME Type to File Extension Mapping
|
|
133
|
-
*
|
|
134
|
-
* Maps common MIME types to their standard file extensions.
|
|
135
|
-
* Used by RepresentationStore to save files with proper extensions.
|
|
136
|
-
*/
|
|
137
|
-
/**
|
|
138
|
-
* Get file extension for a MIME type
|
|
139
|
-
*
|
|
140
|
-
* @param mediaType - MIME type (e.g., "text/markdown")
|
|
141
|
-
* @returns File extension with leading dot (e.g., ".md") or ".dat" if unknown
|
|
142
|
-
*
|
|
143
|
-
* @example
|
|
144
|
-
* getExtensionForMimeType('text/markdown') // => '.md'
|
|
145
|
-
* getExtensionForMimeType('image/png') // => '.png'
|
|
146
|
-
* getExtensionForMimeType('unknown/type') // => '.dat'
|
|
147
|
-
*/
|
|
148
|
-
declare function getExtensionForMimeType(mediaType: string): string;
|
|
149
|
-
/**
|
|
150
|
-
* Derive a file:// storage URI from a resource name and MIME type.
|
|
151
|
-
*
|
|
152
|
-
* @example
|
|
153
|
-
* deriveStorageUri("My Document", "text/markdown") // => "file://my-document.md"
|
|
154
|
-
*/
|
|
155
|
-
declare function deriveStorageUri(name: string, format: string): string;
|
|
156
|
-
/**
|
|
157
|
-
* Check if a MIME type has a known extension mapping
|
|
158
|
-
*
|
|
159
|
-
* @param mediaType - MIME type to check
|
|
160
|
-
* @returns true if extension is known, false if would fallback to .dat
|
|
161
|
-
*/
|
|
162
|
-
declare function hasKnownExtension(mediaType: string): boolean;
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Checksum utilities for content verification
|
|
166
|
-
*/
|
|
167
|
-
/**
|
|
168
|
-
* Calculate SHA-256 checksum of content
|
|
169
|
-
* @param content The content to hash
|
|
170
|
-
* @returns Hex-encoded SHA-256 hash
|
|
171
|
-
*/
|
|
172
|
-
declare function calculateChecksum(content: string | Buffer): string;
|
|
173
|
-
/**
|
|
174
|
-
* Verify content against a checksum
|
|
175
|
-
* @param content The content to verify
|
|
176
|
-
* @param checksum The expected checksum
|
|
177
|
-
* @returns True if content matches checksum
|
|
4
|
+
* Working tree storage for project resources.
|
|
178
5
|
*/
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
export {
|
|
6
|
+
export { WorkingTreeStore, ChecksumMismatchError, type StoredResource, } from './working-tree-store';
|
|
7
|
+
export { getExtensionForMimeType, hasKnownExtension, deriveStorageUri, } from './mime-extensions';
|
|
8
|
+
export { calculateChecksum, verifyChecksum } from './checksum';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIME Type to File Extension Mapping
|
|
3
|
+
*
|
|
4
|
+
* Maps common MIME types to their standard file extensions.
|
|
5
|
+
* Used by RepresentationStore to save files with proper extensions.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Get file extension for a MIME type
|
|
9
|
+
*
|
|
10
|
+
* @param mediaType - MIME type (e.g., "text/markdown")
|
|
11
|
+
* @returns File extension with leading dot (e.g., ".md") or ".dat" if unknown
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* getExtensionForMimeType('text/markdown') // => '.md'
|
|
15
|
+
* getExtensionForMimeType('image/png') // => '.png'
|
|
16
|
+
* getExtensionForMimeType('unknown/type') // => '.dat'
|
|
17
|
+
*/
|
|
18
|
+
export declare function getExtensionForMimeType(mediaType: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Derive a file:// storage URI from a resource name and MIME type.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* deriveStorageUri("My Document", "text/markdown") // => "file://my-document.md"
|
|
24
|
+
*/
|
|
25
|
+
export declare function deriveStorageUri(name: string, format: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a MIME type has a known extension mapping
|
|
28
|
+
*
|
|
29
|
+
* @param mediaType - MIME type to check
|
|
30
|
+
* @returns true if extension is known, false if would fallback to .dat
|
|
31
|
+
*/
|
|
32
|
+
export declare function hasKnownExtension(mediaType: string): boolean;
|
|
33
|
+
//# sourceMappingURL=mime-extensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mime-extensions.d.ts","sourceRoot":"","sources":["../src/mime-extensions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA0FH;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CASjE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOrE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAG5D"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RepresentationStore - Content-addressed storage for byte-level resource representations
|
|
3
|
+
*
|
|
4
|
+
* Handles storage and retrieval of concrete byte-level renditions of resources.
|
|
5
|
+
* Uses content-addressed storage where the checksum IS the filename.
|
|
6
|
+
* Supports multiple storage backends (filesystem, S3, IPFS, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Storage structure (filesystem):
|
|
9
|
+
* basePath/representations/{mediaType}/{ab}/{cd}/rep-{checksum}{extension}
|
|
10
|
+
*
|
|
11
|
+
* Where:
|
|
12
|
+
* - {mediaType} is base MIME type with "/" encoded as "~1" (e.g., "text~1markdown")
|
|
13
|
+
* - {ab}/{cd} are first 4 hex digits of checksum for sharding
|
|
14
|
+
* - {checksum} is the raw SHA-256 hex hash (e.g., "5aaa0b72abc123...")
|
|
15
|
+
* - {extension} is derived from base MIME type (.md, .txt, .png, etc.)
|
|
16
|
+
*
|
|
17
|
+
* Example:
|
|
18
|
+
* For content with checksum "5aaa0b72abc123..." and mediaType "text/markdown; charset=iso-8859-1":
|
|
19
|
+
* - Storage path: basePath/representations/text~1markdown/5a/aa/rep-5aaa0b72abc123....md
|
|
20
|
+
* - Stored mediaType: "text/markdown; charset=iso-8859-1" (full type with charset preserved)
|
|
21
|
+
*
|
|
22
|
+
* Character Encoding:
|
|
23
|
+
* - Charset parameters in mediaType are preserved in metadata (e.g., "text/plain; charset=iso-8859-1")
|
|
24
|
+
* - Storage path uses only base MIME type (strips charset for directory structure)
|
|
25
|
+
* - Content stored as raw bytes - charset only affects decoding on retrieval
|
|
26
|
+
*
|
|
27
|
+
* This design provides:
|
|
28
|
+
* - O(1) content retrieval by checksum + mediaType
|
|
29
|
+
* - Automatic deduplication (identical content = same file)
|
|
30
|
+
* - Idempotent storage operations
|
|
31
|
+
* - Proper file extensions for filesystem browsing
|
|
32
|
+
* - Faithful preservation of character encoding metadata
|
|
33
|
+
*/
|
|
34
|
+
import type { SemiontProject } from '@semiont/core/node';
|
|
35
|
+
import type { Logger } from '@semiont/core';
|
|
36
|
+
/**
|
|
37
|
+
* Metadata for a representation being stored
|
|
38
|
+
*/
|
|
39
|
+
export interface RepresentationMetadata {
|
|
40
|
+
mediaType: string;
|
|
41
|
+
filename?: string;
|
|
42
|
+
encoding?: string;
|
|
43
|
+
language?: string;
|
|
44
|
+
rel?: 'original' | 'thumbnail' | 'preview' | 'optimized' | 'derived' | 'other';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Complete representation information
|
|
48
|
+
*/
|
|
49
|
+
export interface StoredRepresentation extends RepresentationMetadata {
|
|
50
|
+
'@id': string;
|
|
51
|
+
byteSize: number;
|
|
52
|
+
checksum: string;
|
|
53
|
+
created: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Interface for representation storage backends
|
|
57
|
+
*/
|
|
58
|
+
export interface RepresentationStore {
|
|
59
|
+
/**
|
|
60
|
+
* Store content and return representation metadata
|
|
61
|
+
*
|
|
62
|
+
* @param content - Raw bytes to store
|
|
63
|
+
* @param metadata - Representation metadata
|
|
64
|
+
* @returns Complete representation info with checksum
|
|
65
|
+
*/
|
|
66
|
+
store(content: Buffer, metadata: RepresentationMetadata): Promise<StoredRepresentation>;
|
|
67
|
+
/**
|
|
68
|
+
* Retrieve content by checksum (content-addressed lookup)
|
|
69
|
+
*
|
|
70
|
+
* @param checksum - Content checksum as raw hex (e.g., "5aaa0b72...")
|
|
71
|
+
* @param mediaType - MIME type (e.g., "text/markdown")
|
|
72
|
+
* @returns Raw bytes
|
|
73
|
+
*/
|
|
74
|
+
retrieve(checksum: string, mediaType: string): Promise<Buffer>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Filesystem implementation of RepresentationStore
|
|
78
|
+
*/
|
|
79
|
+
export declare class FilesystemRepresentationStore implements RepresentationStore {
|
|
80
|
+
private basePath;
|
|
81
|
+
private logger?;
|
|
82
|
+
constructor(project: SemiontProject, logger?: Logger);
|
|
83
|
+
store(content: Buffer, metadata: RepresentationMetadata): Promise<StoredRepresentation>;
|
|
84
|
+
retrieve(checksum: string, mediaType: string): Promise<Buffer>;
|
|
85
|
+
/**
|
|
86
|
+
* Encode media type for filesystem path
|
|
87
|
+
* Replaces "/" with "~1" to avoid directory separators
|
|
88
|
+
*
|
|
89
|
+
* @param mediaType - MIME type (e.g., "text/markdown")
|
|
90
|
+
* @returns Encoded path segment (e.g., "text~1markdown")
|
|
91
|
+
*/
|
|
92
|
+
private encodeMediaType;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=representation-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"representation-store.d.ts","sourceRoot":"","sources":["../src/representation-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;CAChF;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,sBAAsB;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAExF;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAChE;AAED;;GAEG;AACH,qBAAa,6BAA8B,YAAW,mBAAmB;IACvE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM;IAK9C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAwDvF,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyDpE;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;CAGxB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkingTreeStore - Manages files in the project working tree
|
|
3
|
+
*
|
|
4
|
+
* Unlike the old content-addressed RepresentationStore, this store treats
|
|
5
|
+
* the working tree (project root) as the source of truth for file content.
|
|
6
|
+
* Resources are identified by their file:// URI, which is stable across
|
|
7
|
+
* content changes and moves (tracked by events).
|
|
8
|
+
*
|
|
9
|
+
* Two write paths:
|
|
10
|
+
* - store(content, storageUri): Write bytes to disk (API/GUI/AI path).
|
|
11
|
+
* Used when the file does not yet exist and the caller provides content.
|
|
12
|
+
* - register(storageUri, expectedChecksum?): Read an existing file and
|
|
13
|
+
* return its metadata (CLI path). The file is already on disk; we just
|
|
14
|
+
* verify and record it. If expectedChecksum is provided, throws on mismatch.
|
|
15
|
+
*
|
|
16
|
+
* Storage layout:
|
|
17
|
+
* {projectRoot}/{path-from-uri}
|
|
18
|
+
*
|
|
19
|
+
* For example, storageUri "file://docs/overview.md" resolves to
|
|
20
|
+
* {projectRoot}/docs/overview.md
|
|
21
|
+
*/
|
|
22
|
+
import type { SemiontProject } from '@semiont/core/node';
|
|
23
|
+
import type { Logger } from '@semiont/core';
|
|
24
|
+
/**
|
|
25
|
+
* Result of store() or register()
|
|
26
|
+
*/
|
|
27
|
+
export interface StoredResource {
|
|
28
|
+
storageUri: string;
|
|
29
|
+
checksum: string;
|
|
30
|
+
byteSize: number;
|
|
31
|
+
created: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Manages files in the project working tree
|
|
35
|
+
*/
|
|
36
|
+
export declare class WorkingTreeStore {
|
|
37
|
+
private projectRoot;
|
|
38
|
+
private gitSync;
|
|
39
|
+
private logger?;
|
|
40
|
+
constructor(project: SemiontProject, logger?: Logger);
|
|
41
|
+
private shouldRunGit;
|
|
42
|
+
/**
|
|
43
|
+
* Write content to disk at the location indicated by storageUri.
|
|
44
|
+
*
|
|
45
|
+
* API/GUI/AI path: caller provides bytes; file may not yet exist.
|
|
46
|
+
*
|
|
47
|
+
* @param content - Raw bytes to write
|
|
48
|
+
* @param storageUri - file:// URI (e.g. "file://docs/overview.md")
|
|
49
|
+
* @returns Stored resource metadata
|
|
50
|
+
*/
|
|
51
|
+
store(content: Buffer, storageUri: string, options?: {
|
|
52
|
+
noGit?: boolean;
|
|
53
|
+
}): Promise<StoredResource>;
|
|
54
|
+
/**
|
|
55
|
+
* Read an existing file and return its metadata.
|
|
56
|
+
*
|
|
57
|
+
* CLI path: the file is already on disk. We read it to compute the checksum.
|
|
58
|
+
* If expectedChecksum is provided, throws ChecksumMismatchError on mismatch.
|
|
59
|
+
*
|
|
60
|
+
* @param storageUri - file:// URI (e.g. "file://docs/overview.md")
|
|
61
|
+
* @param expectedChecksum - Optional SHA-256 to verify against
|
|
62
|
+
* @returns Stored resource metadata
|
|
63
|
+
* @throws ChecksumMismatchError if expectedChecksum is provided and does not match
|
|
64
|
+
* @throws Error if file does not exist
|
|
65
|
+
*/
|
|
66
|
+
register(storageUri: string, expectedChecksum?: string, options?: {
|
|
67
|
+
noGit?: boolean;
|
|
68
|
+
}): Promise<StoredResource>;
|
|
69
|
+
/**
|
|
70
|
+
* Read file content by URI.
|
|
71
|
+
*
|
|
72
|
+
* @param storageUri - file:// URI
|
|
73
|
+
* @returns Raw bytes
|
|
74
|
+
*/
|
|
75
|
+
retrieve(storageUri: string): Promise<Buffer>;
|
|
76
|
+
/**
|
|
77
|
+
* Move a file from one URI to another.
|
|
78
|
+
*
|
|
79
|
+
* If .git/ exists in the project root and noGit is not set, runs `git mv`.
|
|
80
|
+
* Otherwise (no .git/ or noGit: true), runs fs.rename.
|
|
81
|
+
*
|
|
82
|
+
* @param fromUri - Current file:// URI
|
|
83
|
+
* @param toUri - New file:// URI
|
|
84
|
+
* @param options.noGit - Skip git mv even if .git/ is present
|
|
85
|
+
*/
|
|
86
|
+
move(fromUri: string, toUri: string, options?: {
|
|
87
|
+
noGit?: boolean;
|
|
88
|
+
}): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Remove a file from the working tree.
|
|
91
|
+
*
|
|
92
|
+
* If .git/ exists and noGit is not set:
|
|
93
|
+
* - keepFile false (default): runs `git rm` (removes from index and disk)
|
|
94
|
+
* - keepFile true: runs `git rm --cached` (removes from index only, file stays on disk)
|
|
95
|
+
* If no .git/ or noGit: true:
|
|
96
|
+
* - keepFile false: runs fs.unlink
|
|
97
|
+
* - keepFile true: no-op on filesystem
|
|
98
|
+
*
|
|
99
|
+
* @param storageUri - file:// URI
|
|
100
|
+
* @param options.noGit - Skip git rm even if .git/ is present
|
|
101
|
+
* @param options.keepFile - Remove from git index only; leave file on disk
|
|
102
|
+
*/
|
|
103
|
+
remove(storageUri: string, options?: {
|
|
104
|
+
noGit?: boolean;
|
|
105
|
+
keepFile?: boolean;
|
|
106
|
+
}): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Convert a file:// URI to an absolute filesystem path.
|
|
109
|
+
*
|
|
110
|
+
* "file://docs/overview.md" → "{projectRoot}/docs/overview.md"
|
|
111
|
+
*
|
|
112
|
+
* @param storageUri - file:// URI
|
|
113
|
+
* @returns Absolute path
|
|
114
|
+
*/
|
|
115
|
+
resolveUri(storageUri: string): string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Thrown when a registered file's checksum does not match the expected value.
|
|
119
|
+
* This indicates the file on disk differs from what was recorded (e.g. modified
|
|
120
|
+
* after staging, or wrong file path provided).
|
|
121
|
+
*/
|
|
122
|
+
export declare class ChecksumMismatchError extends Error {
|
|
123
|
+
readonly storageUri: string;
|
|
124
|
+
readonly expected: string;
|
|
125
|
+
readonly actual: string;
|
|
126
|
+
constructor(storageUri: string, expected: string, actual: string);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=working-tree-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree-store.d.ts","sourceRoot":"","sources":["../src/working-tree-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG5C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM;IAMpD,OAAO,CAAC,YAAY;IAIpB;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAuBxG;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IA0BrH;;;;;OAKG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYnD;;;;;;;;;OASG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBxF;;;;;;;;;;;;;OAaG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkClG;;;;;;;OAOG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;CAOvC;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAE5C,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAFd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM;CAQ1B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semiont/content",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Content-addressed storage for resource representations",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "npm run typecheck && tsup",
|
|
19
|
+
"build": "npm run typecheck && tsup && tsc -p tsconfig.build.json",
|
|
20
20
|
"typecheck": "tsc --noEmit",
|
|
21
21
|
"clean": "rm -rf dist",
|
|
22
22
|
"test": "vitest run",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@vitest/coverage-v8": "^4.1.0",
|
|
31
31
|
"tsup": "^8.0.1",
|
|
32
|
-
"typescript": "^
|
|
32
|
+
"typescript": "^6.0.2"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"content",
|