@mks2508/hyperdiff-utils 0.1.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.
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Error handling for the Hyperdiff engine.
3
+ *
4
+ * Maps FFI error codes (u16 from errors.zig ErrorCode enum)
5
+ * to structured ResultError<HyperdiffErrorCode> from @mks2508/no-throw.
6
+ *
7
+ * Every error code, message, and domain is 1:1 with errors.zig.
8
+ */
9
+ import type { ResultError } from '@mks2508/no-throw';
10
+ /** All valid Hyperdiff error code string literals. */
11
+ export type HyperdiffErrorCode = 'FILE_NOT_FOUND' | 'PERMISSION_DENIED' | 'FILE_READ_ERROR' | 'FILE_WRITE_ERROR' | 'MMAP_FAILED' | 'MMAP_UNMAP_FAILED' | 'FILE_TOO_LARGE' | 'INVALID_PATH' | 'INVALID_UTF8' | 'INVALID_ENCODING' | 'EMPTY_INPUT' | 'HASH_MISMATCH' | 'INVALID_HASH_SIZE' | 'HASH_COLLISION_DETECTED' | 'INVALID_CACHE' | 'CACHE_CORRUPTED' | 'CACHE_VERSION_MISMATCH' | 'CACHE_CHECKSUM_FAILED' | 'CACHE_EXPIRED' | 'CACHE_INCOMPLETE' | 'THREAD_SPAWN_FAILED' | 'THREAD_POOL_EXHAUSTED' | 'THREAD_JOIN_FAILED' | 'THREAD_CANCELLED' | 'THREAD_INVALID_STATE' | 'THREAD_RESOURCE_LIMIT' | 'INVALID_ALGORITHM' | 'ALGORITHM_NOT_SUPPORTED' | 'INTERNAL_ERROR' | 'STACK_OVERFLOW' | 'RECURSION_LIMIT_EXCEEDED' | 'MIDDLE_SNAKE_NOT_FOUND' | 'LCS_NOT_FOUND' | 'EDIT_SCRIPT_INVALID' | 'DIFF_TIMEOUT' | 'DIFF_CANCELLED' | 'INVALID_INPUT' | 'LINE_COUNT_MISMATCH' | 'OFFSET_OUT_OF_BOUNDS' | 'LENGTH_EXCEEDS_BUFFER' | 'NULL_POINTER' | 'INVALID_RANGE' | 'INVALID_PARAMETER' | 'OUT_OF_MEMORY' | 'ALLOCATION_TOO_LARGE' | 'ALLOCATOR_EXHAUSTED' | 'ALLOCATION_FAILED' | 'DOUBLE_FREE' | 'USE_AFTER_FREE' | 'LIBRARY_NOT_FOUND' | 'ABI_MISMATCH' | 'FFI_ERROR' | 'UNKNOWN';
12
+ /** Typed Hyperdiff error — a ResultError with a HyperdiffErrorCode. */
13
+ export type HyperdiffError = ResultError<HyperdiffErrorCode>;
14
+ /** Error domain derived from the numeric FFI error code range. */
15
+ export type HyperdiffErrorDomain = 'io' | 'hash' | 'cache' | 'thread' | 'diff' | 'validation' | 'allocator' | 'unknown';
16
+ /** Numeric error code values matching Zig errors.zig ErrorCode enum(u16). */
17
+ export declare const HYPERDIFF_NUMERIC_CODES: {
18
+ readonly FILE_NOT_FOUND: 1001;
19
+ readonly PERMISSION_DENIED: 1002;
20
+ readonly FILE_READ_ERROR: 1003;
21
+ readonly FILE_WRITE_ERROR: 1004;
22
+ readonly MMAP_FAILED: 1005;
23
+ readonly MMAP_UNMAP_FAILED: 1006;
24
+ readonly FILE_TOO_LARGE: 1007;
25
+ readonly INVALID_PATH: 1008;
26
+ readonly INVALID_UTF8: 2001;
27
+ readonly INVALID_ENCODING: 2002;
28
+ readonly EMPTY_INPUT: 2003;
29
+ readonly HASH_MISMATCH: 2004;
30
+ readonly INVALID_HASH_SIZE: 2005;
31
+ readonly HASH_COLLISION_DETECTED: 2006;
32
+ readonly INVALID_CACHE: 3001;
33
+ readonly CACHE_CORRUPTED: 3002;
34
+ readonly CACHE_VERSION_MISMATCH: 3003;
35
+ readonly CACHE_CHECKSUM_FAILED: 3004;
36
+ readonly CACHE_EXPIRED: 3005;
37
+ readonly CACHE_INCOMPLETE: 3006;
38
+ readonly THREAD_SPAWN_FAILED: 4001;
39
+ readonly THREAD_POOL_EXHAUSTED: 4002;
40
+ readonly THREAD_JOIN_FAILED: 4003;
41
+ readonly THREAD_CANCELLED: 4004;
42
+ readonly THREAD_INVALID_STATE: 4005;
43
+ readonly THREAD_RESOURCE_LIMIT: 4006;
44
+ readonly INVALID_ALGORITHM: 5001;
45
+ readonly ALGORITHM_NOT_SUPPORTED: 5002;
46
+ readonly INTERNAL_ERROR: 5003;
47
+ readonly STACK_OVERFLOW: 5004;
48
+ readonly RECURSION_LIMIT_EXCEEDED: 5005;
49
+ readonly MIDDLE_SNAKE_NOT_FOUND: 5006;
50
+ readonly LCS_NOT_FOUND: 5007;
51
+ readonly EDIT_SCRIPT_INVALID: 5008;
52
+ readonly DIFF_TIMEOUT: 5009;
53
+ readonly DIFF_CANCELLED: 5010;
54
+ readonly INVALID_INPUT: 6001;
55
+ readonly LINE_COUNT_MISMATCH: 6002;
56
+ readonly OFFSET_OUT_OF_BOUNDS: 6003;
57
+ readonly LENGTH_EXCEEDS_BUFFER: 6004;
58
+ readonly NULL_POINTER: 6005;
59
+ readonly INVALID_RANGE: 6006;
60
+ readonly INVALID_PARAMETER: 6007;
61
+ readonly OUT_OF_MEMORY: 7001;
62
+ readonly ALLOCATION_TOO_LARGE: 7002;
63
+ readonly ALLOCATOR_EXHAUSTED: 7003;
64
+ readonly ALLOCATION_FAILED: 7004;
65
+ readonly DOUBLE_FREE: 7005;
66
+ readonly USE_AFTER_FREE: 7006;
67
+ };
68
+ /**
69
+ * Get the error domain from a numeric FFI error code.
70
+ * @param numericCode - The u16 value from DiffResult.error_code
71
+ * @returns The domain category
72
+ */
73
+ export declare function getErrorDomain(numericCode: number): HyperdiffErrorDomain;
74
+ /**
75
+ * Convert a numeric FFI error code to a string error code.
76
+ * @param numericCode - The u16 from DiffResult.error_code
77
+ * @returns String code like 'OUT_OF_MEMORY', or 'UNKNOWN'
78
+ */
79
+ export declare function numericToCode(numericCode: number): HyperdiffErrorCode;
80
+ /**
81
+ * Get the human-readable message for a numeric error code.
82
+ * @param numericCode - The u16 from DiffResult.error_code
83
+ * @returns Message matching errors.zig errorMessage()
84
+ */
85
+ export declare function errorCodeToMessage(numericCode: number): string;
86
+ /**
87
+ * Create a ResultError<HyperdiffErrorCode> from a numeric FFI error code.
88
+ *
89
+ * @param numericCode - The u16 from DiffResult.error_code
90
+ * @returns Structured ResultError with typed code and message
91
+ */
92
+ export declare function createHyperdiffError(numericCode: number): HyperdiffError;
93
+ /**
94
+ * Create a ResultError for engine-level errors (not from Zig FFI).
95
+ *
96
+ * @param code - Engine error code (e.g., 'ABI_MISMATCH', 'FFI_ERROR')
97
+ * @param message - Human-readable description
98
+ * @param cause - Optional underlying Error
99
+ * @returns Structured ResultError
100
+ */
101
+ export declare function createEngineError(code: 'LIBRARY_NOT_FOUND' | 'ABI_MISMATCH' | 'FFI_ERROR' | 'UNKNOWN', message: string, cause?: Error): HyperdiffError;
package/dist/errors.js ADDED
@@ -0,0 +1,163 @@
1
+ import { resultError } from "@mks2508/no-throw";
2
+ //#region src/errors.ts
3
+ /** Numeric error code values matching Zig errors.zig ErrorCode enum(u16). */
4
+ const HYPERDIFF_NUMERIC_CODES = {
5
+ FILE_NOT_FOUND: 1001,
6
+ PERMISSION_DENIED: 1002,
7
+ FILE_READ_ERROR: 1003,
8
+ FILE_WRITE_ERROR: 1004,
9
+ MMAP_FAILED: 1005,
10
+ MMAP_UNMAP_FAILED: 1006,
11
+ FILE_TOO_LARGE: 1007,
12
+ INVALID_PATH: 1008,
13
+ INVALID_UTF8: 2001,
14
+ INVALID_ENCODING: 2002,
15
+ EMPTY_INPUT: 2003,
16
+ HASH_MISMATCH: 2004,
17
+ INVALID_HASH_SIZE: 2005,
18
+ HASH_COLLISION_DETECTED: 2006,
19
+ INVALID_CACHE: 3001,
20
+ CACHE_CORRUPTED: 3002,
21
+ CACHE_VERSION_MISMATCH: 3003,
22
+ CACHE_CHECKSUM_FAILED: 3004,
23
+ CACHE_EXPIRED: 3005,
24
+ CACHE_INCOMPLETE: 3006,
25
+ THREAD_SPAWN_FAILED: 4001,
26
+ THREAD_POOL_EXHAUSTED: 4002,
27
+ THREAD_JOIN_FAILED: 4003,
28
+ THREAD_CANCELLED: 4004,
29
+ THREAD_INVALID_STATE: 4005,
30
+ THREAD_RESOURCE_LIMIT: 4006,
31
+ INVALID_ALGORITHM: 5001,
32
+ ALGORITHM_NOT_SUPPORTED: 5002,
33
+ INTERNAL_ERROR: 5003,
34
+ STACK_OVERFLOW: 5004,
35
+ RECURSION_LIMIT_EXCEEDED: 5005,
36
+ MIDDLE_SNAKE_NOT_FOUND: 5006,
37
+ LCS_NOT_FOUND: 5007,
38
+ EDIT_SCRIPT_INVALID: 5008,
39
+ DIFF_TIMEOUT: 5009,
40
+ DIFF_CANCELLED: 5010,
41
+ INVALID_INPUT: 6001,
42
+ LINE_COUNT_MISMATCH: 6002,
43
+ OFFSET_OUT_OF_BOUNDS: 6003,
44
+ LENGTH_EXCEEDS_BUFFER: 6004,
45
+ NULL_POINTER: 6005,
46
+ INVALID_RANGE: 6006,
47
+ INVALID_PARAMETER: 6007,
48
+ OUT_OF_MEMORY: 7001,
49
+ ALLOCATION_TOO_LARGE: 7002,
50
+ ALLOCATOR_EXHAUSTED: 7003,
51
+ ALLOCATION_FAILED: 7004,
52
+ DOUBLE_FREE: 7005,
53
+ USE_AFTER_FREE: 7006
54
+ };
55
+ /** Human-readable messages matching errors.zig errorMessage() 1:1. */
56
+ const ERROR_MESSAGES = {
57
+ 1001: "File not found",
58
+ 1002: "Permission denied",
59
+ 1003: "Failed to read file",
60
+ 1004: "Failed to write file",
61
+ 1005: "Memory mapping failed",
62
+ 1006: "Failed to unmap memory",
63
+ 1007: "File too large",
64
+ 1008: "Invalid file path",
65
+ 2001: "Invalid UTF-8 sequence",
66
+ 2002: "Invalid text encoding",
67
+ 2003: "Input is empty",
68
+ 2004: "Hash mismatch detected",
69
+ 2005: "Invalid hash size",
70
+ 2006: "Hash collision detected",
71
+ 3001: "Invalid cache structure",
72
+ 3002: "Cache data is corrupted",
73
+ 3003: "Cache version mismatch",
74
+ 3004: "Cache checksum verification failed",
75
+ 3005: "Cache has expired",
76
+ 3006: "Cache data is incomplete",
77
+ 4001: "Failed to spawn thread",
78
+ 4002: "Thread pool exhausted",
79
+ 4003: "Failed to join thread",
80
+ 4004: "Thread was cancelled",
81
+ 4005: "Thread in invalid state",
82
+ 4006: "Thread resource limit reached",
83
+ 5001: "Invalid algorithm specified",
84
+ 5002: "Algorithm not supported",
85
+ 5003: "Internal error occurred",
86
+ 5004: "Stack overflow in diff algorithm",
87
+ 5005: "Recursion limit exceeded",
88
+ 5006: "Middle snake not found",
89
+ 5007: "LCS not found",
90
+ 5008: "Edit script is invalid",
91
+ 5009: "Diff computation timed out",
92
+ 5010: "Diff computation was cancelled",
93
+ 6001: "Invalid input provided",
94
+ 6002: "Line count mismatch",
95
+ 6003: "Offset is out of bounds",
96
+ 6004: "Length exceeds buffer size",
97
+ 6005: "Null pointer provided",
98
+ 6006: "Invalid range specified",
99
+ 6007: "Invalid parameter",
100
+ 7001: "Out of memory",
101
+ 7002: "Allocation too large",
102
+ 7003: "Allocator exhausted",
103
+ 7004: "Memory allocation failed",
104
+ 7005: "Double free detected",
105
+ 7006: "Use after free detected"
106
+ };
107
+ /** Reverse lookup: numeric code → string code. */
108
+ const NUMERIC_TO_STRING = Object.fromEntries(Object.entries(HYPERDIFF_NUMERIC_CODES).map(([k, v]) => [v, k]));
109
+ /**
110
+ * Get the error domain from a numeric FFI error code.
111
+ * @param numericCode - The u16 value from DiffResult.error_code
112
+ * @returns The domain category
113
+ */
114
+ function getErrorDomain(numericCode) {
115
+ if (numericCode >= 1e3 && numericCode < 1100) return "io";
116
+ if (numericCode >= 2e3 && numericCode < 2100) return "hash";
117
+ if (numericCode >= 3e3 && numericCode < 3100) return "cache";
118
+ if (numericCode >= 4e3 && numericCode < 4100) return "thread";
119
+ if (numericCode >= 5e3 && numericCode < 5100) return "diff";
120
+ if (numericCode >= 6e3 && numericCode < 6100) return "validation";
121
+ if (numericCode >= 7e3 && numericCode < 7100) return "allocator";
122
+ return "unknown";
123
+ }
124
+ /**
125
+ * Convert a numeric FFI error code to a string error code.
126
+ * @param numericCode - The u16 from DiffResult.error_code
127
+ * @returns String code like 'OUT_OF_MEMORY', or 'UNKNOWN'
128
+ */
129
+ function numericToCode(numericCode) {
130
+ return NUMERIC_TO_STRING[numericCode] ?? "UNKNOWN";
131
+ }
132
+ /**
133
+ * Get the human-readable message for a numeric error code.
134
+ * @param numericCode - The u16 from DiffResult.error_code
135
+ * @returns Message matching errors.zig errorMessage()
136
+ */
137
+ function errorCodeToMessage(numericCode) {
138
+ return ERROR_MESSAGES[numericCode] ?? `Unknown error (code: ${numericCode})`;
139
+ }
140
+ /**
141
+ * Create a ResultError<HyperdiffErrorCode> from a numeric FFI error code.
142
+ *
143
+ * @param numericCode - The u16 from DiffResult.error_code
144
+ * @returns Structured ResultError with typed code and message
145
+ */
146
+ function createHyperdiffError(numericCode) {
147
+ return resultError(numericToCode(numericCode), errorCodeToMessage(numericCode));
148
+ }
149
+ /**
150
+ * Create a ResultError for engine-level errors (not from Zig FFI).
151
+ *
152
+ * @param code - Engine error code (e.g., 'ABI_MISMATCH', 'FFI_ERROR')
153
+ * @param message - Human-readable description
154
+ * @param cause - Optional underlying Error
155
+ * @returns Structured ResultError
156
+ */
157
+ function createEngineError(code, message, cause) {
158
+ return resultError(code, message, cause);
159
+ }
160
+ //#endregion
161
+ export { HYPERDIFF_NUMERIC_CODES, createEngineError, createHyperdiffError, errorCodeToMessage, getErrorDomain, numericToCode };
162
+
163
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Error handling for the Hyperdiff engine.\n *\n * Maps FFI error codes (u16 from errors.zig ErrorCode enum)\n * to structured ResultError<HyperdiffErrorCode> from @mks2508/no-throw.\n *\n * Every error code, message, and domain is 1:1 with errors.zig.\n */\nimport type { ResultError } from '@mks2508/no-throw';\nimport { resultError } from '@mks2508/no-throw';\n\n// ── Error Code String Literals ────────────────────────────────────────\n// These are the string codes used in ResultError<C>. Named to match\n// the Zig error set names for traceability.\n\n/** All valid Hyperdiff error code string literals. */\nexport type HyperdiffErrorCode =\n // IO (1000-1099)\n | 'FILE_NOT_FOUND'\n | 'PERMISSION_DENIED'\n | 'FILE_READ_ERROR'\n | 'FILE_WRITE_ERROR'\n | 'MMAP_FAILED'\n | 'MMAP_UNMAP_FAILED'\n | 'FILE_TOO_LARGE'\n | 'INVALID_PATH'\n // Hash (2000-2099)\n | 'INVALID_UTF8'\n | 'INVALID_ENCODING'\n | 'EMPTY_INPUT'\n | 'HASH_MISMATCH'\n | 'INVALID_HASH_SIZE'\n | 'HASH_COLLISION_DETECTED'\n // Cache (3000-3099)\n | 'INVALID_CACHE'\n | 'CACHE_CORRUPTED'\n | 'CACHE_VERSION_MISMATCH'\n | 'CACHE_CHECKSUM_FAILED'\n | 'CACHE_EXPIRED'\n | 'CACHE_INCOMPLETE'\n // Thread (4000-4099)\n | 'THREAD_SPAWN_FAILED'\n | 'THREAD_POOL_EXHAUSTED'\n | 'THREAD_JOIN_FAILED'\n | 'THREAD_CANCELLED'\n | 'THREAD_INVALID_STATE'\n | 'THREAD_RESOURCE_LIMIT'\n // Diff (5000-5099)\n | 'INVALID_ALGORITHM'\n | 'ALGORITHM_NOT_SUPPORTED'\n | 'INTERNAL_ERROR'\n | 'STACK_OVERFLOW'\n | 'RECURSION_LIMIT_EXCEEDED'\n | 'MIDDLE_SNAKE_NOT_FOUND'\n | 'LCS_NOT_FOUND'\n | 'EDIT_SCRIPT_INVALID'\n | 'DIFF_TIMEOUT'\n | 'DIFF_CANCELLED'\n // Validation (6000-6099)\n | 'INVALID_INPUT'\n | 'LINE_COUNT_MISMATCH'\n | 'OFFSET_OUT_OF_BOUNDS'\n | 'LENGTH_EXCEEDS_BUFFER'\n | 'NULL_POINTER'\n | 'INVALID_RANGE'\n | 'INVALID_PARAMETER'\n // Allocator (7000-7099)\n | 'OUT_OF_MEMORY'\n | 'ALLOCATION_TOO_LARGE'\n | 'ALLOCATOR_EXHAUSTED'\n | 'ALLOCATION_FAILED'\n | 'DOUBLE_FREE'\n | 'USE_AFTER_FREE'\n // Engine-level (not from Zig)\n | 'LIBRARY_NOT_FOUND'\n | 'ABI_MISMATCH'\n | 'FFI_ERROR'\n | 'UNKNOWN';\n\n/** Typed Hyperdiff error — a ResultError with a HyperdiffErrorCode. */\nexport type HyperdiffError = ResultError<HyperdiffErrorCode>;\n\n/** Error domain derived from the numeric FFI error code range. */\nexport type HyperdiffErrorDomain =\n | 'io'\n | 'hash'\n | 'cache'\n | 'thread'\n | 'diff'\n | 'validation'\n | 'allocator'\n | 'unknown';\n\n// ── Numeric Code ↔ String Code Mapping ────────────────────────────────\n// Maps the u16 values from errors.zig ErrorCode enum to string literals.\n\n/** Numeric error code values matching Zig errors.zig ErrorCode enum(u16). */\nexport const HYPERDIFF_NUMERIC_CODES = {\n // IO (1000-1099)\n FILE_NOT_FOUND: 1001,\n PERMISSION_DENIED: 1002,\n FILE_READ_ERROR: 1003,\n FILE_WRITE_ERROR: 1004,\n MMAP_FAILED: 1005,\n MMAP_UNMAP_FAILED: 1006,\n FILE_TOO_LARGE: 1007,\n INVALID_PATH: 1008,\n // Hash (2000-2099)\n INVALID_UTF8: 2001,\n INVALID_ENCODING: 2002,\n EMPTY_INPUT: 2003,\n HASH_MISMATCH: 2004,\n INVALID_HASH_SIZE: 2005,\n HASH_COLLISION_DETECTED: 2006,\n // Cache (3000-3099)\n INVALID_CACHE: 3001,\n CACHE_CORRUPTED: 3002,\n CACHE_VERSION_MISMATCH: 3003,\n CACHE_CHECKSUM_FAILED: 3004,\n CACHE_EXPIRED: 3005,\n CACHE_INCOMPLETE: 3006,\n // Thread (4000-4099)\n THREAD_SPAWN_FAILED: 4001,\n THREAD_POOL_EXHAUSTED: 4002,\n THREAD_JOIN_FAILED: 4003,\n THREAD_CANCELLED: 4004,\n THREAD_INVALID_STATE: 4005,\n THREAD_RESOURCE_LIMIT: 4006,\n // Diff (5000-5099)\n INVALID_ALGORITHM: 5001,\n ALGORITHM_NOT_SUPPORTED: 5002,\n INTERNAL_ERROR: 5003,\n STACK_OVERFLOW: 5004,\n RECURSION_LIMIT_EXCEEDED: 5005,\n MIDDLE_SNAKE_NOT_FOUND: 5006,\n LCS_NOT_FOUND: 5007,\n EDIT_SCRIPT_INVALID: 5008,\n DIFF_TIMEOUT: 5009,\n DIFF_CANCELLED: 5010,\n // Validation (6000-6099)\n INVALID_INPUT: 6001,\n LINE_COUNT_MISMATCH: 6002,\n OFFSET_OUT_OF_BOUNDS: 6003,\n LENGTH_EXCEEDS_BUFFER: 6004,\n NULL_POINTER: 6005,\n INVALID_RANGE: 6006,\n INVALID_PARAMETER: 6007,\n // Allocator (7000-7099)\n OUT_OF_MEMORY: 7001,\n ALLOCATION_TOO_LARGE: 7002,\n ALLOCATOR_EXHAUSTED: 7003,\n ALLOCATION_FAILED: 7004,\n DOUBLE_FREE: 7005,\n USE_AFTER_FREE: 7006,\n} as const satisfies Record<string, number>;\n\n/** Human-readable messages matching errors.zig errorMessage() 1:1. */\nconst ERROR_MESSAGES: Record<number, string> = {\n // IO\n 1001: 'File not found',\n 1002: 'Permission denied',\n 1003: 'Failed to read file',\n 1004: 'Failed to write file',\n 1005: 'Memory mapping failed',\n 1006: 'Failed to unmap memory',\n 1007: 'File too large',\n 1008: 'Invalid file path',\n // Hash\n 2001: 'Invalid UTF-8 sequence',\n 2002: 'Invalid text encoding',\n 2003: 'Input is empty',\n 2004: 'Hash mismatch detected',\n 2005: 'Invalid hash size',\n 2006: 'Hash collision detected',\n // Cache\n 3001: 'Invalid cache structure',\n 3002: 'Cache data is corrupted',\n 3003: 'Cache version mismatch',\n 3004: 'Cache checksum verification failed',\n 3005: 'Cache has expired',\n 3006: 'Cache data is incomplete',\n // Thread\n 4001: 'Failed to spawn thread',\n 4002: 'Thread pool exhausted',\n 4003: 'Failed to join thread',\n 4004: 'Thread was cancelled',\n 4005: 'Thread in invalid state',\n 4006: 'Thread resource limit reached',\n // Diff\n 5001: 'Invalid algorithm specified',\n 5002: 'Algorithm not supported',\n 5003: 'Internal error occurred',\n 5004: 'Stack overflow in diff algorithm',\n 5005: 'Recursion limit exceeded',\n 5006: 'Middle snake not found',\n 5007: 'LCS not found',\n 5008: 'Edit script is invalid',\n 5009: 'Diff computation timed out',\n 5010: 'Diff computation was cancelled',\n // Validation\n 6001: 'Invalid input provided',\n 6002: 'Line count mismatch',\n 6003: 'Offset is out of bounds',\n 6004: 'Length exceeds buffer size',\n 6005: 'Null pointer provided',\n 6006: 'Invalid range specified',\n 6007: 'Invalid parameter',\n // Allocator\n 7001: 'Out of memory',\n 7002: 'Allocation too large',\n 7003: 'Allocator exhausted',\n 7004: 'Memory allocation failed',\n 7005: 'Double free detected',\n 7006: 'Use after free detected',\n};\n\n/** Reverse lookup: numeric code → string code. */\nconst NUMERIC_TO_STRING: Record<number, HyperdiffErrorCode> = Object.fromEntries(\n Object.entries(HYPERDIFF_NUMERIC_CODES).map(([k, v]) => [v, k as HyperdiffErrorCode]),\n) as Record<number, HyperdiffErrorCode>;\n\n/**\n * Get the error domain from a numeric FFI error code.\n * @param numericCode - The u16 value from DiffResult.error_code\n * @returns The domain category\n */\nexport function getErrorDomain(numericCode: number): HyperdiffErrorDomain {\n if (numericCode >= 1000 && numericCode < 1100) return 'io';\n if (numericCode >= 2000 && numericCode < 2100) return 'hash';\n if (numericCode >= 3000 && numericCode < 3100) return 'cache';\n if (numericCode >= 4000 && numericCode < 4100) return 'thread';\n if (numericCode >= 5000 && numericCode < 5100) return 'diff';\n if (numericCode >= 6000 && numericCode < 6100) return 'validation';\n if (numericCode >= 7000 && numericCode < 7100) return 'allocator';\n return 'unknown';\n}\n\n/**\n * Convert a numeric FFI error code to a string error code.\n * @param numericCode - The u16 from DiffResult.error_code\n * @returns String code like 'OUT_OF_MEMORY', or 'UNKNOWN'\n */\nexport function numericToCode(numericCode: number): HyperdiffErrorCode {\n return NUMERIC_TO_STRING[numericCode] ?? 'UNKNOWN';\n}\n\n/**\n * Get the human-readable message for a numeric error code.\n * @param numericCode - The u16 from DiffResult.error_code\n * @returns Message matching errors.zig errorMessage()\n */\nexport function errorCodeToMessage(numericCode: number): string {\n return ERROR_MESSAGES[numericCode] ?? `Unknown error (code: ${numericCode})`;\n}\n\n/**\n * Create a ResultError<HyperdiffErrorCode> from a numeric FFI error code.\n *\n * @param numericCode - The u16 from DiffResult.error_code\n * @returns Structured ResultError with typed code and message\n */\nexport function createHyperdiffError(numericCode: number): HyperdiffError {\n const code = numericToCode(numericCode);\n const message = errorCodeToMessage(numericCode);\n return resultError(code, message);\n}\n\n/**\n * Create a ResultError for engine-level errors (not from Zig FFI).\n *\n * @param code - Engine error code (e.g., 'ABI_MISMATCH', 'FFI_ERROR')\n * @param message - Human-readable description\n * @param cause - Optional underlying Error\n * @returns Structured ResultError\n */\nexport function createEngineError(\n code: 'LIBRARY_NOT_FOUND' | 'ABI_MISMATCH' | 'FFI_ERROR' | 'UNKNOWN',\n message: string,\n cause?: Error,\n): HyperdiffError {\n return resultError(code, message, cause);\n}\n"],"mappings":";;;AAiGA,MAAa,0BAA0B;CAErC,gBAAgB;CAChB,mBAAmB;CACnB,iBAAiB;CACjB,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,gBAAgB;CAChB,cAAc;CAEd,cAAc;CACd,kBAAkB;CAClB,aAAa;CACb,eAAe;CACf,mBAAmB;CACnB,yBAAyB;CAEzB,eAAe;CACf,iBAAiB;CACjB,wBAAwB;CACxB,uBAAuB;CACvB,eAAe;CACf,kBAAkB;CAElB,qBAAqB;CACrB,uBAAuB;CACvB,oBAAoB;CACpB,kBAAkB;CAClB,sBAAsB;CACtB,uBAAuB;CAEvB,mBAAmB;CACnB,yBAAyB;CACzB,gBAAgB;CAChB,gBAAgB;CAChB,0BAA0B;CAC1B,wBAAwB;CACxB,eAAe;CACf,qBAAqB;CACrB,cAAc;CACd,gBAAgB;CAEhB,eAAe;CACf,qBAAqB;CACrB,sBAAsB;CACtB,uBAAuB;CACvB,cAAc;CACd,eAAe;CACf,mBAAmB;CAEnB,eAAe;CACf,sBAAsB;CACtB,qBAAqB;CACrB,mBAAmB;CACnB,aAAa;CACb,gBAAgB;CACjB;;AAGD,MAAM,iBAAyC;CAE7C,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACP;;AAGD,MAAM,oBAAwD,OAAO,YACnE,OAAO,QAAQ,wBAAwB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,EAAwB,CAAC,CACtF;;;;;;AAOD,SAAgB,eAAe,aAA2C;AACxE,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,KAAI,eAAe,OAAQ,cAAc,KAAM,QAAO;AACtD,QAAO;;;;;;;AAQT,SAAgB,cAAc,aAAyC;AACrE,QAAO,kBAAkB,gBAAgB;;;;;;;AAQ3C,SAAgB,mBAAmB,aAA6B;AAC9D,QAAO,eAAe,gBAAgB,wBAAwB,YAAY;;;;;;;;AAS5E,SAAgB,qBAAqB,aAAqC;AAGxE,QAAO,YAFM,cAAc,YAAY,EACvB,mBAAmB,YAAY,CACd;;;;;;;;;;AAWnC,SAAgB,kBACd,MACA,SACA,OACgB;AAChB,QAAO,YAAY,MAAM,SAAS,MAAM"}
@@ -0,0 +1,4 @@
1
+ export * from './result';
2
+ export * from './errors';
3
+ export * from './types';
4
+ export { createLogger } from './logger';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { UNKNOWN_ERROR, all, collect, createCancelledOp, createFailedOp, createFailedState, createIdleOp, createInitialState, createLoadingState, createPendingOp, createRevalidatingState, createSuccessOp, createSuccessState, err, fail, flatMap, fromPromise, hasData, isErr, isFailed, isInitial, isLoading, isOk, isOpActive, isOpCancelled, isOpDone, isOpFailed, isOpIdle, isOpPending, isOpSuccess, isPending, isRevalidating, isSuccess, map, mapErr, match, ok, opDuration, opElapsed, resultError, tap, tapErr, tryCatch, tryCatchAsync, unwrap, unwrapOr, unwrapOrElse } from "./result.js";
2
+ import { HYPERDIFF_NUMERIC_CODES, createEngineError, createHyperdiffError, errorCodeToMessage, getErrorDomain, numericToCode } from "./errors.js";
3
+ import { createLogger } from "./logger.js";
4
+ export { HYPERDIFF_NUMERIC_CODES, UNKNOWN_ERROR, all, collect, createCancelledOp, createEngineError, createFailedOp, createFailedState, createHyperdiffError, createIdleOp, createInitialState, createLoadingState, createLogger, createPendingOp, createRevalidatingState, createSuccessOp, createSuccessState, err, errorCodeToMessage, fail, flatMap, fromPromise, getErrorDomain, hasData, isErr, isFailed, isInitial, isLoading, isOk, isOpActive, isOpCancelled, isOpDone, isOpFailed, isOpIdle, isOpPending, isOpSuccess, isPending, isRevalidating, isSuccess, map, mapErr, match, numericToCode, ok, opDuration, opElapsed, resultError, tap, tapErr, tryCatch, tryCatchAsync, unwrap, unwrapOr, unwrapOrElse };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Create a scoped logger for a Hyperdiff component.
3
+ * @param component - Component name (e.g., 'FFI', 'Engine', 'BunAdapter')
4
+ * @returns Scoped logger instance
5
+ */
6
+ export declare function createLogger(component: string): import("@mks2508/better-logger").ComponentLogger;
package/dist/logger.js ADDED
@@ -0,0 +1,19 @@
1
+ import logger from "@mks2508/better-logger";
2
+ //#region src/logger.ts
3
+ /**
4
+ * Logger wrapper for Hyperdiff packages.
5
+ *
6
+ * Re-exports from @mks2508/better-logger with a preset component prefix.
7
+ */
8
+ /**
9
+ * Create a scoped logger for a Hyperdiff component.
10
+ * @param component - Component name (e.g., 'FFI', 'Engine', 'BunAdapter')
11
+ * @returns Scoped logger instance
12
+ */
13
+ function createLogger(component) {
14
+ return logger.component(`hyperdiff:${component}`);
15
+ }
16
+ //#endregion
17
+ export { createLogger };
18
+
19
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["/**\n * Logger wrapper for Hyperdiff packages.\n *\n * Re-exports from @mks2508/better-logger with a preset component prefix.\n */\nimport logger from '@mks2508/better-logger';\n\n/**\n * Create a scoped logger for a Hyperdiff component.\n * @param component - Component name (e.g., 'FFI', 'Engine', 'BunAdapter')\n * @returns Scoped logger instance\n */\nexport function createLogger(component: string) {\n return logger.component(`hyperdiff:${component}`);\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,aAAa,WAAmB;AAC9C,QAAO,OAAO,UAAU,aAAa,YAAY"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Result pattern re-exports from @mks2508/no-throw v0.2.0.
3
+ *
4
+ * Exposes the full API: Result type, constructors, guards, transforms,
5
+ * pattern matching, collection ops, exception wrapping, TransactionState,
6
+ * and OperationState.
7
+ */
8
+ export { ok, err, fail, resultError, UNKNOWN_ERROR, } from '@mks2508/no-throw';
9
+ export type { Result, Ok, Err, ResultError, ErrorCode, } from '@mks2508/no-throw';
10
+ export { isOk, isErr } from '@mks2508/no-throw';
11
+ export { unwrap, unwrapOr, unwrapOrElse } from '@mks2508/no-throw';
12
+ export { map, mapErr, flatMap } from '@mks2508/no-throw';
13
+ export { tap, tapErr } from '@mks2508/no-throw';
14
+ export { match } from '@mks2508/no-throw';
15
+ export { collect, all } from '@mks2508/no-throw';
16
+ export { fromPromise, tryCatch, tryCatchAsync } from '@mks2508/no-throw';
17
+ export type { TransactionState } from '@mks2508/no-throw';
18
+ export { createInitialState, createLoadingState, createRevalidatingState, createSuccessState, createFailedState, isInitial, isLoading, isRevalidating, isSuccess, isFailed, isPending, hasData, } from '@mks2508/no-throw';
19
+ export type { OperationState, OperationStatus, IOperationProgress, IProgressEvent, } from '@mks2508/no-throw';
20
+ export { createIdleOp, createPendingOp, createSuccessOp, createFailedOp, createCancelledOp, isOpIdle, isOpPending, isOpSuccess, isOpFailed, isOpCancelled, isOpActive, isOpDone, opDuration, opElapsed, } from '@mks2508/no-throw';
package/dist/result.js ADDED
@@ -0,0 +1,2 @@
1
+ import { UNKNOWN_ERROR, all, collect, createCancelledOp, createFailedOp, createFailedState, createIdleOp, createInitialState, createLoadingState, createPendingOp, createRevalidatingState, createSuccessOp, createSuccessState, err, fail, flatMap, fromPromise, hasData, isErr, isFailed, isInitial, isLoading, isOk, isOpActive, isOpCancelled, isOpDone, isOpFailed, isOpIdle, isOpPending, isOpSuccess, isPending, isRevalidating, isSuccess, map, mapErr, match, ok, opDuration, opElapsed, resultError, tap, tapErr, tryCatch, tryCatchAsync, unwrap, unwrapOr, unwrapOrElse } from "@mks2508/no-throw";
2
+ export { UNKNOWN_ERROR, all, collect, createCancelledOp, createFailedOp, createFailedState, createIdleOp, createInitialState, createLoadingState, createPendingOp, createRevalidatingState, createSuccessOp, createSuccessState, err, fail, flatMap, fromPromise, hasData, isErr, isFailed, isInitial, isLoading, isOk, isOpActive, isOpCancelled, isOpDone, isOpFailed, isOpIdle, isOpPending, isOpSuccess, isPending, isRevalidating, isSuccess, map, mapErr, match, ok, opDuration, opElapsed, resultError, tap, tapErr, tryCatch, tryCatchAsync, unwrap, unwrapOr, unwrapOrElse };
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Shared FFI adapter types.
3
+ *
4
+ * These types are used across all runtime-specific FFI adapters
5
+ * (ffi-bun, ffi-deno, napi) and the engine package.
6
+ */
7
+ /**
8
+ * Raw FFI result before TypeScript conversion.
9
+ * Matches Zig DiffResult extern struct layout (16 bytes on 64-bit):
10
+ * [0..8) edits pointer (u64)
11
+ * [8..12) edit_count (u32)
12
+ * [12..16) error_code (u32)
13
+ */
14
+ export interface IRawDiffResult {
15
+ /** Pointer to the CEdit array (Zig-owned memory). */
16
+ editsPtr: number;
17
+ /** Number of edits in the array. */
18
+ editCount: number;
19
+ /** Error code: 0 = success, non-zero = HyperdiffErrorCode numeric value. */
20
+ errorCode: number;
21
+ }
22
+ /**
23
+ * Low-level diff edit read from CEdit pointer.
24
+ * Matches Zig CEdit extern struct (20 bytes):
25
+ * [0] tag (u8)
26
+ * [1..4) _pad (3 bytes)
27
+ * [4..8) old_start (u32)
28
+ * [8..12) old_end (u32)
29
+ * [12..16) new_start (u32)
30
+ * [16..20) new_end (u32)
31
+ */
32
+ export interface IRawDiffEdit {
33
+ tag: number;
34
+ oldStart: number;
35
+ oldEnd: number;
36
+ newStart: number;
37
+ newEnd: number;
38
+ }
39
+ /**
40
+ * Raw FFI result for metadata generation.
41
+ * Matches Zig MetadataResult extern struct layout.
42
+ */
43
+ export interface IRawMetadataResult {
44
+ /** Pointer to the CHunk array (Zig-owned memory). */
45
+ hunksPtr: number;
46
+ /** Number of hunks. */
47
+ hunkCount: number;
48
+ /** Pointer to the CContent array (Zig-owned memory). */
49
+ contentsPtr: number;
50
+ /** Total number of content entries. */
51
+ contentCount: number;
52
+ /** Total rendered line count in split view (including collapsed). */
53
+ splitLineCount: number;
54
+ /** Total rendered line count in unified view (including collapsed). */
55
+ unifiedLineCount: number;
56
+ /** Total lines in old file. */
57
+ oldLineCount: number;
58
+ /** Total lines in new file. */
59
+ newLineCount: number;
60
+ /** Error code: 0 = success, non-zero = failure. */
61
+ errorCode: number;
62
+ }
63
+ /**
64
+ * Raw hunk metadata read from CHunk pointer.
65
+ * Matches Zig CHunk extern struct (64 bytes).
66
+ */
67
+ export interface IRawHunk {
68
+ /** Unchanged lines between previous hunk end and this hunk start. */
69
+ collapsedBefore: number;
70
+ /** Starting line in new file (1-based). */
71
+ additionStart: number;
72
+ /** Total new-file lines in this hunk (context + additions). */
73
+ additionCount: number;
74
+ /** Count of added lines only. */
75
+ additionLines: number;
76
+ /** 0-based index into full new-file line array. */
77
+ additionLineIndex: number;
78
+ /** Starting line in old file (1-based). */
79
+ deletionStart: number;
80
+ /** Total old-file lines in this hunk (context + deletions). */
81
+ deletionCount: number;
82
+ /** Count of deleted lines only. */
83
+ deletionLines: number;
84
+ /** 0-based index into full old-file line array. */
85
+ deletionLineIndex: number;
86
+ /** Starting rendered line index in split view. */
87
+ splitLineStart: number;
88
+ /** Rendered line count in split view. */
89
+ splitLineCount: number;
90
+ /** Starting rendered line index in unified view. */
91
+ unifiedLineStart: number;
92
+ /** Rendered line count in unified view. */
93
+ unifiedLineCount: number;
94
+ /** Index into CContent array where this hunk's entries begin. */
95
+ contentOffset: number;
96
+ /** Number of CContent entries for this hunk. */
97
+ contentCount: number;
98
+ /** 1 if new file has no trailing newline at this hunk's end. */
99
+ noEofcrAdditions: number;
100
+ /** 1 if old file has no trailing newline at this hunk's end. */
101
+ noEofcrDeletions: number;
102
+ }
103
+ /**
104
+ * Raw content entry read from CContent pointer.
105
+ * Matches Zig CContent extern struct (20 bytes).
106
+ *
107
+ * Tag 0 = context (unchanged lines): param1 = line count, param2 = 0.
108
+ * Tag 1 = change: param1 = additions, param2 = deletions.
109
+ */
110
+ export interface IRawContent {
111
+ /** 0 = context, 1 = change. */
112
+ tag: 0 | 1;
113
+ /** Context: line count. Change: number of additions. */
114
+ param1: number;
115
+ /** Context: 0. Change: number of deletions. */
116
+ param2: number;
117
+ /** 0-based index into new-file line array. */
118
+ additionLineIndex: number;
119
+ /** 0-based index into old-file line array. */
120
+ deletionLineIndex: number;
121
+ }
122
+ /**
123
+ * Adapter interface that runtime-specific FFI packages must implement.
124
+ * The engine package consumes this to provide the high-level diff() API.
125
+ */
126
+ export interface IFFIAdapter {
127
+ /** Compute a diff between two text buffers. Returns raw pointer data. */
128
+ compute(oldText: string, newText: string, algorithm: number): IRawDiffResult;
129
+ /** Free a previously returned DiffResult's edit array. */
130
+ free(resultPtr: number): void;
131
+ /** Health check — returns 42 if library is loaded correctly. */
132
+ ping(): number;
133
+ /** Return CEdit struct size in bytes for ABI validation. */
134
+ ceditSize(): number;
135
+ /** Return ABI version for compatibility check. */
136
+ abiVersion(): number;
137
+ /** Read CEdit array from pointer into TypeScript objects. */
138
+ readEdits(editsPtr: number, editCount: number): IRawDiffEdit[];
139
+ /** Generate Pierre-compatible hunk metadata from two text buffers. */
140
+ metadata(oldText: string, newText: string, algorithm: number, contextLines: number, flags: number): IRawMetadataResult;
141
+ /** Read CHunk array from pointer into TypeScript objects. */
142
+ readHunks(hunksPtr: number, hunkCount: number): IRawHunk[];
143
+ /** Read CContent array from pointer into TypeScript objects. */
144
+ readContents(contentsPtr: number, contentCount: number): IRawContent[];
145
+ /** Free a MetadataResult previously returned by metadata(). */
146
+ metadataFree(hunksPtr: number, hunkCount: number, contentsPtr: number, contentCount: number): void;
147
+ /**
148
+ * Generate unified diff patch directly from two text buffers.
149
+ * Returns the patch string. Algorithm: 0=myers, 1=histogram, 2=onp, 255=auto.
150
+ */
151
+ patch(oldText: string, newText: string, algorithm: number, contextLines: number): string;
152
+ /**
153
+ * Compute inline (word or char level) diff between two single lines.
154
+ * Mode: 0=word, 1=char. Returns array of inline edits with byte offsets.
155
+ */
156
+ inlineDiff(oldLine: string, newLine: string, mode: number): IRawDiffEdit[];
157
+ /** Runtime identifier for debugging. */
158
+ readonly runtime: 'ffi-bun' | 'ffi-deno' | 'napi';
159
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@mks2508/hyperdiff-utils",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./result": {
16
+ "import": "./dist/result.js",
17
+ "types": "./dist/result.d.ts"
18
+ },
19
+ "./logger": {
20
+ "import": "./dist/logger.js",
21
+ "types": "./dist/logger.d.ts"
22
+ },
23
+ "./errors": {
24
+ "import": "./dist/errors.js",
25
+ "types": "./dist/errors.d.ts"
26
+ }
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "build": "rm -rf dist && ../../../node_modules/.bin/rolldown --config rolldown.config.ts && ../../../node_modules/.bin/tsc --emitDeclarationOnly",
33
+ "typecheck": "tsc --noEmit",
34
+ "dev": "../../../node_modules/.bin/rolldown --config rolldown.config.ts --watch"
35
+ },
36
+ "dependencies": {
37
+ "@mks2508/better-logger": "^4.0.0",
38
+ "@mks2508/no-throw": "^0.2.0"
39
+ }
40
+ }