automerge-js adding trace to out of date errors

This commit is contained in:
Orion Henry 2022-08-26 14:15:01 -05:00
parent e6cd366aa0
commit 59bde120ee
6 changed files with 38 additions and 18 deletions

View file

@ -3,6 +3,7 @@
//const CACHE = Symbol('_cache') // map from objectId to immutable object
export const STATE = Symbol.for('_am_state') // object containing metadata about current state (e.g. sequence numbers)
export const HEADS = Symbol.for('_am_heads') // object containing metadata about current state (e.g. sequence numbers)
export const TRACE = Symbol.for('_am_trace') // object containing metadata about current state (e.g. sequence numbers)
export const OBJECT_ID = Symbol.for('_am_objectId') // object containing metadata about current state (e.g. sequence numbers)
export const READ_ONLY = Symbol.for('_am_readOnly') // object containing metadata about current state (e.g. sequence numbers)
export const FROZEN = Symbol.for('_am_frozen') // object containing metadata about current state (e.g. sequence numbers)

View file

@ -2,7 +2,7 @@
export { uuid } from './uuid'
import { rootProxy, listProxy, textProxy, mapProxy } from "./proxies"
import { STATE, HEADS, OBJECT_ID, READ_ONLY, FROZEN } from "./constants"
import { STATE, HEADS, TRACE, OBJECT_ID, READ_ONLY, FROZEN } from "./constants"
import { AutomergeValue, Counter } from "./types"
export { AutomergeValue, Text, Counter, Int, Uint, Float64 } from "./types"
@ -48,6 +48,20 @@ function _heads<T>(doc: Doc<T>) : Heads | undefined {
return Reflect.get(doc,HEADS)
}
function _trace<T>(doc: Doc<T>) : string | undefined {
return Reflect.get(doc,TRACE)
}
function _set_heads<T>(doc: Doc<T>, heads: Heads) {
Reflect.set(doc,HEADS,heads)
Reflect.set(doc,TRACE,(new Error()).stack)
}
function _clear_heads<T>(doc: Doc<T>) {
Reflect.set(doc,HEADS,undefined)
Reflect.set(doc,TRACE,undefined)
}
function _obj<T>(doc: Doc<T>) : ObjID {
return Reflect.get(doc,OBJECT_ID)
}
@ -104,7 +118,7 @@ function _change<T>(doc: Doc<T>, options: ChangeOptions, callback: ChangeFn<T>):
throw new RangeError("Attempting to use an outdated Automerge document")
}
if (!!_heads(doc) === true) {
throw new RangeError("Attempting to change an out of date document");
throw new RangeError("Attempting to change an out of date document - set at: " + _trace(doc));
}
if (_readonly(doc) === false) {
throw new RangeError("Calls to Automerge.change cannot be nested")
@ -112,13 +126,13 @@ function _change<T>(doc: Doc<T>, options: ChangeOptions, callback: ChangeFn<T>):
const state = _state(doc)
const heads = state.getHeads()
try {
Reflect.set(doc,HEADS,heads)
_set_heads(doc,heads)
Reflect.set(doc,FROZEN,true)
const root : T = rootProxy(state);
callback(root)
if (state.pendingOps() === 0) {
Reflect.set(doc,FROZEN,false)
Reflect.set(doc,HEADS,undefined)
_clear_heads(doc)
return doc
} else {
state.commit(options.message, options.time)
@ -127,7 +141,7 @@ function _change<T>(doc: Doc<T>, options: ChangeOptions, callback: ChangeFn<T>):
} catch (e) {
//console.log("ERROR: ",e)
Reflect.set(doc,FROZEN,false)
Reflect.set(doc,HEADS,undefined)
_clear_heads(doc)
state.rollback()
throw e
}
@ -168,14 +182,14 @@ export function save<T>(doc: Doc<T>) : Uint8Array {
export function merge<T>(local: Doc<T>, remote: Doc<T>) : Doc<T> {
if (!!_heads(local) === true) {
throw new RangeError("Attempting to change an out of date document");
throw new RangeError("Attempting to change an out of date document - set at: " + _trace(doc));
}
const localState = _state(local)
const heads = localState.getHeads()
const remoteState = _state(remote)
const changes = localState.getChangesAdded(remoteState)
localState.applyChanges(changes)
Reflect.set(local,HEADS,heads)
_set_heads(local,heads)
return rootProxy(localState, true)
}
@ -267,7 +281,7 @@ export function applyChanges<T>(doc: Doc<T>, changes: Change[]) : [Doc<T>] {
const state = _state(doc)
const heads = state.getHeads()
state.applyChanges(changes)
Reflect.set(doc,HEADS,heads)
_set_heads(doc,heads)
return [rootProxy(state, true)];
}
@ -322,7 +336,7 @@ export function receiveSyncMessage<T>(doc: Doc<T>, inState: SyncState, message:
throw new RangeError("Attempting to use an outdated Automerge document")
}
if (!!_heads(doc) === true) {
throw new RangeError("Attempting to change an out of date document");
throw new RangeError("Attempting to change an out of date document - set at: " + _trace(doc));
}
if (_readonly(doc) === false) {
throw new RangeError("Calls to Automerge.change cannot be nested")
@ -330,7 +344,7 @@ export function receiveSyncMessage<T>(doc: Doc<T>, inState: SyncState, message:
const state = _state(doc)
const heads = state.getHeads()
state.receiveSyncMessage(syncState, message)
Reflect.set(doc,HEADS,heads)
_set_heads(doc,heads)
const outState = ApiHandler.exportSyncState(syncState)
return [rootProxy(state, true), outState, null];
}

View file

@ -5,7 +5,7 @@ import { AutomergeValue, ScalarValue, MapValue, ListValue, TextValue } from "./t
import { Int, Uint, Float64 } from "./numbers"
import { Counter, getWriteableCounter } from "./counter"
import { Text } from "./text"
import { STATE, HEADS, FROZEN, OBJECT_ID, READ_ONLY, COUNTER, INT, UINT, F64, TEXT } from "./constants"
import { STATE, HEADS, TRACE, FROZEN, OBJECT_ID, READ_ONLY, COUNTER, INT, UINT, F64, TEXT } from "./constants"
function parseListIndex(key) {
if (typeof key === 'string' && /^[0-9]+$/.test(key)) key = parseInt(key, 10)
@ -108,6 +108,7 @@ const MapHandler = {
if (key === READ_ONLY) return readonly
if (key === FROZEN) return frozen
if (key === HEADS) return heads
if (key === TRACE) return target.trace
if (key === STATE) return context;
if (!cache[key]) {
cache[key] = valueAt(target, key)
@ -129,6 +130,10 @@ const MapHandler = {
target.heads = val
return true
}
if (key === TRACE) {
target.trace = val
return true
}
const [ value, datatype ] = import_value(val)
if (frozen) {
throw new RangeError("Attempting to use an outdated Automerge document")
@ -211,6 +216,7 @@ const ListHandler = {
if (index === READ_ONLY) return readonly
if (index === FROZEN) return frozen
if (index === HEADS) return heads
if (index === TRACE) return target.trace
if (index === STATE) return context;
if (index === 'length') return context.length(objectId, heads);
if (index === Symbol.iterator) {
@ -246,6 +252,10 @@ const ListHandler = {
target.heads = val
return true
}
if (index === TRACE) {
target.trace = val
return true
}
if (typeof index == "string") {
throw new RangeError('list index must be a number')
}
@ -356,6 +366,7 @@ const TextHandler = Object.assign({}, ListHandler, {
if (index === READ_ONLY) return readonly
if (index === FROZEN) return frozen
if (index === HEADS) return heads
if (index === TRACE) return target.trace
if (index === STATE) return context;
if (index === 'length') return context.length(objectId, heads);
if (index === Symbol.iterator) {

View file

@ -2,6 +2,4 @@ let wasm = require("./bindgen")
module.exports = wasm
module.exports.load = module.exports.loadDoc
delete module.exports.loadDoc
Object.defineProperty(module.exports, "__esModule", { value: true })
module.exports.init = () => (new Promise((resolve,reject) => { resolve(module.exports) }))
module.exports.default = module.exports.init

View file

@ -205,5 +205,5 @@ export class SyncState {
readonly sharedHeads: Heads;
}
export default function init (): Promise<API>;
export function init (): Promise<API>;

View file

@ -47,7 +47,3 @@ export function init() {
}))
}
// depricating default export
export default function() {
return init()
}