@@ -41,6 +41,60 @@ import { getValueAtPath } from "../path-utils.ts";
4141import { getJSONFromDataURI } from "../uri-utils.ts" ;
4242import { ignoreReadForScheduling } from "../scheduler.ts" ;
4343
44+ /**
45+ * NotFoundError implementation for transaction-shim
46+ */
47+ class NotFoundError extends RangeError implements INotFoundError {
48+ override readonly name = "NotFoundError" as const ;
49+ public readonly source : IAttestation ;
50+ public readonly address : IMemorySpaceAddress ;
51+ private readonly space ?: MemorySpace ;
52+
53+ constructor (
54+ message : string ,
55+ id : string ,
56+ path : readonly MemoryAddressPathComponent [ ] = [ ] ,
57+ value ?: JSONValue ,
58+ space ?: MemorySpace ,
59+ ) {
60+ super ( message ) ;
61+ this . space = space ;
62+ // Ensure id has a valid URI format for type compatibility
63+ const uri = id . includes ( ":" ) ? id as `${string } :${string } ` : `of:${ id } ` as `${string } :${string } `;
64+ this . address = {
65+ id : uri ,
66+ type : "application/json" ,
67+ path : [ ...path ] , // Convert readonly to mutable array
68+ space : space || "" as MemorySpace ,
69+ } ;
70+ this . source = {
71+ address : {
72+ id : uri ,
73+ type : "application/json" ,
74+ path : [ ] ,
75+ } ,
76+ value,
77+ } ;
78+ }
79+
80+ /**
81+ * @deprecated Use `address.path` instead. This property exists for backward compatibility.
82+ */
83+ get path ( ) : MemoryAddressPathComponent [ ] {
84+ return [ ...this . address . path ] ;
85+ }
86+
87+ from ( space : MemorySpace ) : INotFoundError {
88+ return new NotFoundError (
89+ this . message ,
90+ this . address . id ,
91+ [ ...this . address . path ] , // Convert to mutable array
92+ this . source . value ,
93+ space ,
94+ ) ;
95+ }
96+ }
97+
4498/**
4599 * Convert a URI string to an EntityId object
46100 */
@@ -57,6 +111,7 @@ export function uriToEntityId(uri: string): EntityId {
57111function validateParentPath (
58112 value : any ,
59113 path : readonly MemoryAddressPathComponent [ ] ,
114+ id : string ,
60115) : INotFoundError | null {
61116 const pathLength = path . length ;
62117
@@ -67,11 +122,12 @@ function validateParentPath(
67122 // Check if the document itself exists and is an object for first-level writes
68123 if ( pathLength === 1 ) {
69124 if ( value === undefined || ! isRecord ( value ) ) {
70- const pathError : INotFoundError = new Error (
125+ return new NotFoundError (
71126 `Cannot access path [${ String ( path [ 0 ] ) } ] - document is not a record` ,
72- ) as INotFoundError ;
73- pathError . name = "NotFoundError" ;
74- return pathError ;
127+ id ,
128+ [ ...path ] ,
129+ value ,
130+ ) ;
75131 }
76132 return null ;
77133 }
@@ -92,17 +148,15 @@ function validateParentPath(
92148 if (
93149 value === undefined || parentValue === undefined || ! isRecord ( parentValue )
94150 ) {
95- const pathError : INotFoundError = new Error (
151+ const errorPath = ( parentIndex > 0 ) ? path . slice ( 0 , parentIndex - 1 ) : [ ] ;
152+ return new NotFoundError (
96153 `Cannot access path [${ path . join ( ", " ) } ] - parent path [${
97154 path . slice ( 0 , lastIndex ) . join ( ", " )
98155 } ] does not exist or is not a record`,
99- ) as INotFoundError ;
100- pathError . name = "NotFoundError" ;
101-
102- // Set pathError.path to last valid parent path component
103- if ( parentIndex > 0 ) pathError . path = path . slice ( 0 , parentIndex - 1 ) ;
104-
105- return pathError ;
156+ id ,
157+ errorPath ,
158+ value ,
159+ ) ;
106160 }
107161
108162 return null ;
@@ -201,7 +255,7 @@ class TransactionReader implements ITransactionReader {
201255 try {
202256 const json = getJSONFromDataURI ( address . id ) ;
203257
204- const validationError = validateParentPath ( json , address . path ) ;
258+ const validationError = validateParentPath ( json , address . path , address . id ) ;
205259 if ( validationError ) {
206260 return { ok : undefined , error : validationError } ;
207261 }
@@ -239,25 +293,31 @@ class TransactionReader implements ITransactionReader {
239293 ) ;
240294
241295 if ( ! doc ) {
242- const notFoundError : INotFoundError = new Error (
296+ const notFoundError = new NotFoundError (
243297 `Document not found: ${ address . id } ` ,
244- ) as INotFoundError ;
245- notFoundError . name = "NotFoundError" ;
298+ address . id ,
299+ [ ] ,
300+ undefined ,
301+ address . space ,
302+ ) ;
246303 return { ok : undefined , error : notFoundError } ;
247304 }
248305
249306 // Path-based logic
250307 if ( ! address . path . length ) {
251- const notFoundError : INotFoundError = new Error (
308+ const notFoundError = new NotFoundError (
252309 `Path must not be empty` ,
253- ) as INotFoundError ;
254- notFoundError . name = "NotFoundError" ;
310+ address . id ,
311+ [ ] ,
312+ undefined ,
313+ address . space ,
314+ ) ;
255315 return { ok : undefined , error : notFoundError } ;
256316 }
257317 const [ first , ...rest ] = address . path ;
258318 if ( first === "value" ) {
259319 // Validate parent path exists and is a record for nested writes/reads
260- const validationError = validateParentPath ( doc . get ( ) , rest ) ;
320+ const validationError = validateParentPath ( doc . get ( ) , rest , address . id ) ;
261321 if ( validationError ) {
262322 return { ok : undefined , error : validationError } ;
263323 }
@@ -272,10 +332,13 @@ class TransactionReader implements ITransactionReader {
272332 } else if ( first === "source" ) {
273333 // Only allow path length 1
274334 if ( rest . length > 0 ) {
275- const notFoundError : INotFoundError = new Error (
335+ const notFoundError = new NotFoundError (
276336 `Path beyond 'source' is not allowed` ,
277- ) as INotFoundError ;
278- notFoundError . name = "NotFoundError" ;
337+ address . id ,
338+ [ ...address . path ] ,
339+ undefined ,
340+ address . space ,
341+ ) ;
279342 return { ok : undefined , error : notFoundError } ;
280343 }
281344 // Return the URI of the sourceCell if it exists
@@ -292,10 +355,13 @@ class TransactionReader implements ITransactionReader {
292355 this . journal . addRead ( address , options ) ;
293356 return { ok : read } ;
294357 } else {
295- const notFoundError : INotFoundError = new Error (
358+ const notFoundError = new NotFoundError (
296359 `Invalid first path element: ${ String ( first ) } ` ,
297- ) as INotFoundError ;
298- notFoundError . name = "NotFoundError" ;
360+ address . id ,
361+ [ ...address . path ] ,
362+ undefined ,
363+ address . space ,
364+ ) ;
299365 return { ok : undefined , error : notFoundError } ;
300366 }
301367 }
@@ -369,16 +435,19 @@ class TransactionWriter extends TransactionReader
369435
370436 // Path-based logic
371437 if ( ! address . path . length ) {
372- const notFoundError : INotFoundError = new Error (
438+ const notFoundError = new NotFoundError (
373439 `Path must not be empty` ,
374- ) as INotFoundError ;
375- notFoundError . name = "NotFoundError" ;
440+ address . id ,
441+ [ ] ,
442+ undefined ,
443+ address . space ,
444+ ) ;
376445 return { ok : undefined , error : notFoundError } ;
377446 }
378447 const [ first , ...rest ] = address . path ;
379448 if ( first === "value" ) {
380449 // Validate parent path exists and is a record for nested writes
381- const validationError = validateParentPath ( doc . get ( ) , rest ) ;
450+ const validationError = validateParentPath ( doc . get ( ) , rest , address . id ) ;
382451 if ( validationError ) {
383452 return { ok : undefined , error : validationError } ;
384453 }
@@ -398,18 +467,24 @@ class TransactionWriter extends TransactionReader
398467 } else if ( first === "source" ) {
399468 // Only allow path length 1
400469 if ( rest . length > 0 ) {
401- const notFoundError : INotFoundError = new Error (
470+ const notFoundError = new NotFoundError (
402471 `Path beyond 'source' is not allowed` ,
403- ) as INotFoundError ;
404- notFoundError . name = "NotFoundError" ;
472+ address . id ,
473+ [ ...address . path ] ,
474+ undefined ,
475+ address . space ,
476+ ) ;
405477 return { ok : undefined , error : notFoundError } ;
406478 }
407479 // Value must be a URI string (of:...)
408480 if ( typeof value !== "string" || ! value . startsWith ( "of:" ) ) {
409- const notFoundError : INotFoundError = new Error (
481+ const notFoundError = new NotFoundError (
410482 `Value for 'source' must be a URI string (of:...)` ,
411- ) as INotFoundError ;
412- notFoundError . name = "NotFoundError" ;
483+ address . id ,
484+ [ ...address . path ] ,
485+ value ,
486+ address . space ,
487+ ) ;
413488 return { ok : undefined , error : notFoundError } ;
414489 }
415490 // Get the source doc in the same space
@@ -420,10 +495,13 @@ class TransactionWriter extends TransactionReader
420495 false ,
421496 ) ;
422497 if ( ! sourceDoc ) {
423- const notFoundError : INotFoundError = new Error (
498+ const notFoundError = new NotFoundError (
424499 `Source document not found: ${ value } ` ,
425- ) as INotFoundError ;
426- notFoundError . name = "NotFoundError" ;
500+ address . id ,
501+ [ ...address . path ] ,
502+ value ,
503+ address . space ,
504+ ) ;
427505 return { ok : undefined , error : notFoundError } ;
428506 }
429507 doc . sourceCell = sourceDoc ;
@@ -434,10 +512,13 @@ class TransactionWriter extends TransactionReader
434512 this . journal . addWrite ( address ) ;
435513 return { ok : write } ;
436514 } else {
437- const notFoundError : INotFoundError = new Error (
515+ const notFoundError = new NotFoundError (
438516 `Invalid first path element: ${ String ( first ) } ` ,
439- ) as INotFoundError ;
440- notFoundError . name = "NotFoundError" ;
517+ address . id ,
518+ [ ...address . path ] ,
519+ undefined ,
520+ address . space ,
521+ ) ;
441522 return { ok : undefined , error : notFoundError } ;
442523 }
443524 }
@@ -646,7 +727,7 @@ export class ExtendedStorageTransaction implements IExtendedStorageTransaction {
646727 const writeResult = this . tx . write ( address , value ) ;
647728 if ( writeResult . error && writeResult . error . name === "NotFoundError" ) {
648729 // Create parent entries if needed
649- const lastValidPath = writeResult . error . path ;
730+ const lastValidPath = ( writeResult . error as INotFoundError ) . path ;
650731 const valueObj = lastValidPath
651732 ? this . readValueOrThrow ( { ...address , path : lastValidPath } , {
652733 meta : ignoreReadForScheduling ,
0 commit comments