@@ -1229,6 +1229,182 @@ describe("Chronicle", () => {
12291229 expect ( result . ok ! . value ) . toEqual ( { hello : "world" } ) ;
12301230 } ) ;
12311231
1232+ it ( "should fail to write to data URI at root level" , ( ) => {
1233+ const address = {
1234+ id : 'data:application/json,{"hello":"world"}' as const ,
1235+ type : "application/json" as const ,
1236+ path : [ ] ,
1237+ } ;
1238+
1239+ const chronicle = Chronicle . open ( replica ) ;
1240+ const result = chronicle . write ( address , { hello : "updated" } ) ;
1241+
1242+ expect ( result . error ) . toBeDefined ( ) ;
1243+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1244+ expect ( result . error ! . message ) . toContain (
1245+ "Cannot write to read-only address" ,
1246+ ) ;
1247+ expect ( result . error ! . message ) . toContain ( address . id ) ;
1248+ expect ( result . error ! . address ) . toEqual ( address ) ;
1249+ } ) ;
1250+
1251+ it ( "should fail to write to nested path in data URI" , ( ) => {
1252+ const address = {
1253+ id : 'data:application/json,{"user":{"name":"Alice"}}' as const ,
1254+ type : "application/json" as const ,
1255+ path : [ "user" , "name" ] ,
1256+ } ;
1257+
1258+ const chronicle = Chronicle . open ( replica ) ;
1259+ const result = chronicle . write ( address , "Bob" ) ;
1260+
1261+ expect ( result . error ) . toBeDefined ( ) ;
1262+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1263+ expect ( result . error ! . address ) . toEqual ( address ) ;
1264+ } ) ;
1265+
1266+ it ( "should fail to write undefined (delete) to data URI" , ( ) => {
1267+ const address = {
1268+ id : 'data:application/json,{"hello":"world"}' as const ,
1269+ type : "application/json" as const ,
1270+ path : [ "hello" ] ,
1271+ } ;
1272+
1273+ const chronicle = Chronicle . open ( replica ) ;
1274+ const result = chronicle . write ( address , undefined ) ;
1275+
1276+ expect ( result . error ) . toBeDefined ( ) ;
1277+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1278+ } ) ;
1279+
1280+ it ( "should fail to write to base64 encoded data URI" , ( ) => {
1281+ const address = {
1282+ id : "data:application/json;base64,eyJoZWxsbyI6IndvcmxkIn0=" as const ,
1283+ type : "application/json" as const ,
1284+ path : [ ] ,
1285+ } ;
1286+
1287+ const chronicle = Chronicle . open ( replica ) ;
1288+ const result = chronicle . write ( address , { hello : "updated" } ) ;
1289+
1290+ expect ( result . error ) . toBeDefined ( ) ;
1291+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1292+ } ) ;
1293+
1294+ it ( "should fail to write to text/plain data URI" , ( ) => {
1295+ const address = {
1296+ id : "data:text/plain,hello%20world" as const ,
1297+ type : "text/plain" as const ,
1298+ path : [ ] ,
1299+ } ;
1300+
1301+ const chronicle = Chronicle . open ( replica ) ;
1302+ const result = chronicle . write ( address , "goodbye world" ) ;
1303+
1304+ expect ( result . error ) . toBeDefined ( ) ;
1305+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1306+ } ) ;
1307+
1308+ it ( "should allow writes to regular addresses after failing to write to data URI" , ( ) => {
1309+ const dataUriAddress = {
1310+ id : 'data:application/json,{"hello":"world"}' as const ,
1311+ type : "application/json" as const ,
1312+ path : [ ] ,
1313+ } ;
1314+
1315+ const regularAddress = {
1316+ id : "test:regular" ,
1317+ type : "application/json" ,
1318+ path : [ ] ,
1319+ } as const ;
1320+
1321+ const chronicle = Chronicle . open ( replica ) ;
1322+
1323+ // First, fail to write to data URI
1324+ const dataUriResult = chronicle . write ( dataUriAddress , {
1325+ hello : "updated" ,
1326+ } ) ;
1327+ expect ( dataUriResult . error ) . toBeDefined ( ) ;
1328+ expect ( dataUriResult . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1329+
1330+ // Then, successfully write to regular address
1331+ const regularResult = chronicle . write ( regularAddress , {
1332+ status : "active" ,
1333+ } ) ;
1334+ expect ( regularResult . ok ) . toBeDefined ( ) ;
1335+ expect ( regularResult . ok ! . value ) . toEqual ( { status : "active" } ) ;
1336+ } ) ;
1337+
1338+ it ( "should check for data URI before any other validation" , ( ) => {
1339+ // This tests that we check for data URI early, before loading or rebasing
1340+ const address = {
1341+ id : 'data:application/json,{"complex":{"nested":"value"}}' as const ,
1342+ type : "application/json" as const ,
1343+ path : [ "complex" , "nested" ] ,
1344+ } ;
1345+
1346+ const chronicle = Chronicle . open ( replica ) ;
1347+ const result = chronicle . write ( address , "new value" ) ;
1348+
1349+ // Should fail immediately with ReadOnlyAddressError, not with any other error
1350+ expect ( result . error ) . toBeDefined ( ) ;
1351+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1352+ } ) ;
1353+
1354+ it ( "should handle data URI with special characters in write attempt" , ( ) => {
1355+ const address = {
1356+ id :
1357+ "data:application/json,%7B%22key%22%3A%22value%20with%20spaces%22%7D" as const ,
1358+ type : "application/json" as const ,
1359+ path : [ ] ,
1360+ } ;
1361+
1362+ const chronicle = Chronicle . open ( replica ) ;
1363+ const result = chronicle . write ( address , { key : "new value" } ) ;
1364+
1365+ expect ( result . error ) . toBeDefined ( ) ;
1366+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1367+ } ) ;
1368+
1369+ it ( "should fail to write to array element in data URI" , ( ) => {
1370+ const address = {
1371+ id : 'data:application/json,["a","b","c"]' as const ,
1372+ type : "application/json" as const ,
1373+ path : [ "1" ] ,
1374+ } ;
1375+
1376+ const chronicle = Chronicle . open ( replica ) ;
1377+ const result = chronicle . write ( address , "B" ) ;
1378+
1379+ expect ( result . error ) . toBeDefined ( ) ;
1380+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1381+ } ) ;
1382+
1383+ it ( "should provide helpful error message with the data URI" , ( ) => {
1384+ const longDataUri = `data:application/json,${
1385+ encodeURIComponent ( JSON . stringify ( {
1386+ users : Array ( 10 ) . fill ( null ) . map ( ( _ , i ) => ( {
1387+ id : i ,
1388+ name : `User ${ i } ` ,
1389+ email : `user${ i } @example.com` ,
1390+ } ) ) ,
1391+ } ) )
1392+ } `;
1393+
1394+ const address = {
1395+ id : longDataUri as `data:${string } `,
1396+ type : "application/json" as const ,
1397+ path : [ "users" , "0" , "name" ] as const ,
1398+ } ;
1399+
1400+ const chronicle = Chronicle . open ( replica ) ;
1401+ const result = chronicle . write ( address , "Updated Name" ) ;
1402+
1403+ expect ( result . error ) . toBeDefined ( ) ;
1404+ expect ( result . error ! . name ) . toBe ( "ReadOnlyAddressError" ) ;
1405+ expect ( result . error ! . message ) . toContain ( longDataUri ) ;
1406+ } ) ;
1407+
12321408 it ( "should read base64 encoded JSON data URI" , ( ) => {
12331409 const address = {
12341410 id : "data:application/json;base64,eyJoZWxsbyI6IndvcmxkIn0=" as const ,
0 commit comments