mirror of
https://github.com/appy-one/acebase.git
synced 2026-06-30 06:02:02 -06:00
1 line
No EOL
245 KiB
JavaScript
1 line
No EOL
245 KiB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.acebase=f()}})((function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,(function(r){var n=e[i][1][r];return o(n||r)}),p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AceBaseBase=exports.AceBaseBaseSettings=void 0;const simple_event_emitter_1=require("./simple-event-emitter");const data_reference_1=require("./data-reference");const type_mappings_1=require("./type-mappings");const optional_observable_1=require("./optional-observable");const debug_1=require("./debug");const simple_colors_1=require("./simple-colors");class AceBaseBaseSettings{constructor(options){if(typeof options!=="object"){options={}}this.logLevel=options.logLevel||"log";this.logColors=typeof options.logColors==="boolean"?options.logColors:true;this.info=typeof options.info==="string"?options.info:undefined}}exports.AceBaseBaseSettings=AceBaseBaseSettings;class AceBaseBase extends simple_event_emitter_1.SimpleEventEmitter{constructor(dbname,options){super();options=new AceBaseBaseSettings(options||{});this.name=dbname;this.debug=new debug_1.DebugLogger(options.logLevel,`[${dbname}]`);simple_colors_1.SetColorsEnabled(options.logColors);const logoStyle=[simple_colors_1.ColorStyle.magenta,simple_colors_1.ColorStyle.bold];const logo=" ___ ______ "+"\n"+" / _ \\ | ___ \\ "+"\n"+" / /_\\ \\ ___ ___| |_/ / __ _ ___ ___ "+"\n"+" | _ |/ __/ _ \\ ___ \\/ _` / __|/ _ \\"+"\n"+" | | | | (_| __/ |_/ / (_| \\__ \\ __/"+"\n"+" \\_| |_/\\___\\___\\____/ \\__,_|___/\\___|";const info=options.info?"".padStart(40-options.info.length," ")+options.info+"\n":"";this.debug.write(logo.colorize(logoStyle));info&&this.debug.write(info.colorize(simple_colors_1.ColorStyle.magenta));this.types=new type_mappings_1.TypeMappings(this);this.once("ready",(()=>{this._ready=true}))}ready(callback=undefined){if(this._ready===true){callback&&callback();return Promise.resolve()}else{let resolve;const promise=new Promise((res=>resolve=res));this.on("ready",(()=>{resolve();callback&&callback()}));return promise}}get isReady(){return this._ready===true}setObservable(Observable){optional_observable_1.setObservable(Observable)}ref(path){return new data_reference_1.DataReference(this,path)}get root(){return this.ref("")}query(path){const ref=new data_reference_1.DataReference(this,path);return new data_reference_1.DataReferenceQuery(ref)}get indexes(){return{get:()=>this.api.getIndexes(),create:(path,key,options)=>this.api.createIndex(path,key,options)}}get schema(){return{get:path=>this.api.getSchema(path),set:(path,schema)=>this.api.setSchema(path,schema),all:()=>this.api.getSchemas(),check:(path,value,isUpdate)=>this.api.validateSchema(path,value,isUpdate)}}}exports.AceBaseBase=AceBaseBase},{"./data-reference":8,"./debug":10,"./optional-observable":14,"./simple-colors":21,"./simple-event-emitter":22,"./type-mappings":25}],2:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Api=void 0;class NotImplementedError extends Error{constructor(name){super(`${name} is not implemented`)}}class Api{constructor(dbname,settings,readyCallback){}stats(options){throw new NotImplementedError("stats")}subscribe(path,event,callback,settings){throw new NotImplementedError("subscribe")}unsubscribe(path,event,callback){throw new NotImplementedError("unsubscribe")}update(path,updates,options){throw new NotImplementedError("update")}set(path,value,options){throw new NotImplementedError("set")}get(path,options){throw new NotImplementedError("get")}transaction(path,callback,options){throw new NotImplementedError("transaction")}exists(path){throw new NotImplementedError("exists")}query(path,query,options){throw new NotImplementedError("query")}reflect(path,type,args){throw new NotImplementedError("reflect")}export(path,arg,options){throw new NotImplementedError("export")}import(path,stream,options){throw new NotImplementedError("import")}createIndex(path,key,options){throw new NotImplementedError("createIndex")}getIndexes(){throw new NotImplementedError("getIndexes")}setSchema(path,schema){throw new NotImplementedError("setSchema")}getSchema(path){throw new NotImplementedError("getSchema")}getSchemas(){throw new NotImplementedError("getSchemas")}validateSchema(path,value,isUpdate){throw new NotImplementedError("validateSchema")}getMutations(filter){throw new NotImplementedError("getMutations")}getChanges(filter){throw new NotImplementedError("getChanges")}}exports.Api=Api},{}],3:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ascii85=void 0;const c=function(input,length,result){var i,j,n,b=[0,0,0,0,0];for(i=0;i<length;i+=4){n=((input[i]*256+input[i+1])*256+input[i+2])*256+input[i+3];if(!n){result.push("z")}else{for(j=0;j<5;b[j++]=n%85+33,n=Math.floor(n/85));}result.push(String.fromCharCode(b[4],b[3],b[2],b[1],b[0]))}};function encode(arr){var input=arr;var result=[],remainder=input.length%4,length=input.length-remainder;c(input,length,result);if(remainder){var t=new Uint8Array(4);t.set(input.slice(length),0);c(t,4,result);var x=result.pop();if(x=="z"){x="!!!!!"}result.push(x.substr(0,remainder+1))}var ret=result.join("");ret="<~"+ret+"~>";return ret}exports.ascii85={encode:function(arr){if(arr instanceof ArrayBuffer){arr=new Uint8Array(arr,0,arr.byteLength)}return encode(arr)},decode:function(input){if(!input.startsWith("<~")||!input.endsWith("~>")){throw new Error("Invalid input string")}input=input.substr(2,input.length-4);var n=input.length,r=[],b=[0,0,0,0,0],i,j,t,x,y,d;for(i=0;i<n;++i){if(input.charAt(i)=="z"){r.push(0,0,0,0);continue}for(j=0;j<5;++j){b[j]=input.charCodeAt(i+j)-33}d=n-i;if(d<5){for(j=d;j<4;b[++j]=0);b[d]=85}t=(((b[0]*85+b[1])*85+b[2])*85+b[3])*85+b[4];x=t&255;t>>>=8;y=t&255;t>>>=8;r.push(t>>>8,t&255,y,x);for(j=d;j<5;++j,r.pop());i+=4}const data=new Uint8Array(r);return data.buffer.slice(data.byteOffset,data.byteOffset+data.byteLength)}}},{}],4:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});const pad_1=require("../pad");const env=typeof window==="object"?window:self,globalCount=Object.keys(env).length,mimeTypesLength=navigator.mimeTypes?navigator.mimeTypes.length:0,clientId=pad_1.default((mimeTypesLength+navigator.userAgent.length).toString(36)+globalCount.toString(36),4);function fingerprint(){return clientId}exports.default=fingerprint},{"../pad":6}],5:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});const fingerprint_1=require("./fingerprint");const pad_1=require("./pad");var c=0,blockSize=4,base=36,discreteValues=Math.pow(base,blockSize);function randomBlock(){return pad_1.default((Math.random()*discreteValues<<0).toString(base),blockSize)}function safeCounter(){c=c<discreteValues?c:0;c++;return c-1}function cuid(timebias=0){var letter="c",timestamp=((new Date).getTime()+timebias).toString(base),counter=pad_1.default(safeCounter().toString(base),blockSize),print=fingerprint_1.default(),random=randomBlock()+randomBlock();return letter+timestamp+counter+print+random}exports.default=cuid},{"./fingerprint":4,"./pad":6}],6:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});function pad(num,size){var s="000000000"+num;return s.substr(s.length-size)}exports.default=pad},{}],7:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OrderedCollectionProxy=exports.proxyAccess=exports.LiveDataProxy=void 0;const utils_1=require("./utils");const data_reference_1=require("./data-reference");const data_snapshot_1=require("./data-snapshot");const path_reference_1=require("./path-reference");const id_1=require("./id");const optional_observable_1=require("./optional-observable");const process_1=require("./process");const path_info_1=require("./path-info");const simple_event_emitter_1=require("./simple-event-emitter");class RelativeNodeTarget extends Array{static areEqual(t1,t2){return t1.length===t2.length&&t1.every(((key,i)=>t2[i]===key))}static isAncestor(ancestor,other){return ancestor.length<other.length&&ancestor.every(((key,i)=>other[i]===key))}static isDescendant(descendant,other){return descendant.length>other.length&&other.every(((key,i)=>descendant[i]===key))}}const isProxy=Symbol("isProxy");class LiveDataProxy{static async create(ref,defaultValue){ref=new data_reference_1.DataReference(ref.db,ref.path);let cache,loaded=false;let proxy;const proxyId=id_1.ID.generate();let onMutationCallback;let onErrorCallback=err=>{console.error(err.message,err.details)};const clientSubscriptions=[];const applyChange=(keys,newValue)=>{if(keys.length===0){cache=newValue;return true}const allowCreation=false;if(allowCreation){cache=typeof keys[0]==="number"?[]:{}}let target=cache;const trailKeys=keys.slice();while(trailKeys.length>1){const key=trailKeys.shift();if(!(key in target)){if(allowCreation){target[key]=typeof key==="number"?[]:{}}else{return false}}target=target[key]}const prop=trailKeys.shift();if(newValue===null){target instanceof Array?target.splice(prop,1):delete target[prop]}else{target[prop]=newValue}return true};const syncFallback=async()=>{if(!loaded){return}await reload()};const subscription=ref.on("mutations",{syncFallback:syncFallback}).subscribe((async snap=>{var _a;if(!loaded){return}const context=snap.context();const isRemote=((_a=context.acebase_proxy)===null||_a===void 0?void 0:_a.id)!==proxyId;if(!isRemote){return}const mutations=snap.val(false);const proceed=mutations.every((mutation=>{if(!applyChange(mutation.target,mutation.val)){return false}if(onMutationCallback){const changeRef=mutation.target.reduce(((ref,key)=>ref.child(key)),ref);const changeSnap=new data_snapshot_1.DataSnapshot(changeRef,mutation.val,false,mutation.prev,snap.context());onMutationCallback(changeSnap,isRemote)}return true}));if(proceed){localMutationsEmitter.emit("mutations",{origin:"remote",snap:snap})}else{console.warn(`Cached value of live data proxy on "${ref.path}" appears outdated, will be reloaded`);await reload()}}));let processPromise=Promise.resolve();const mutationQueue=[];const transactions=[];const pushLocalMutations=async()=>{const mutations=[];for(let i=0,m=mutationQueue[0];i<mutationQueue.length;i++,m=mutationQueue[i]){if(!transactions.find((t=>RelativeNodeTarget.areEqual(t.target,m.target)||RelativeNodeTarget.isAncestor(t.target,m.target)))){mutationQueue.splice(i,1);i--;mutations.push(m)}}if(mutations.length===0){return}mutations.forEach((mutation=>{mutation.value=utils_1.cloneObject(getTargetValue(cache,mutation.target))}));process_1.default.nextTick((()=>{const context={acebase_proxy:{id:proxyId,source:"update",local:true}};if(onMutationCallback){mutations.forEach((mutation=>{const mutationRef=mutation.target.reduce(((ref,key)=>ref.child(key)),ref);const mutationSnap=new data_snapshot_1.DataSnapshot(mutationRef,mutation.value,false,mutation.previous,context);onMutationCallback(mutationSnap,false)}))}const snap=new data_snapshot_1.MutationsDataSnapshot(ref,mutations.map((m=>({target:m.target,val:m.value,prev:m.previous}))),context);localMutationsEmitter.emit("mutations",{origin:"local",snap:snap})}));const batchId=id_1.ID.generate();processPromise=mutations.reduce(((mutations,m,i,arr)=>{if(!arr.some((other=>RelativeNodeTarget.isAncestor(other.target,m.target)))){mutations.push(m)}return mutations}),[]).reduce(((updates,m,i,arr)=>{const target=m.target;if(target.length===0){updates.push({ref:ref,value:cache,type:"set"})}else{const parentTarget=target.slice(0,-1);const key=target.slice(-1)[0];const parentRef=parentTarget.reduce(((ref,key)=>ref.child(key)),ref);const parentUpdate=updates.find((update=>update.ref.path===parentRef.path));const cacheValue=getTargetValue(cache,target);if(parentUpdate){parentUpdate.value[key]=cacheValue}else{updates.push({ref:parentRef,value:{[key]:cacheValue},type:"update"})}}return updates}),[]).reduce((async(promise,update,i,updates)=>{await promise;return update.ref.context({acebase_proxy:{id:proxyId,source:"update",update_id:id_1.ID.generate(),batch_id:batchId,batch_updates:updates.length}})[update.type](update.value).catch((err=>{onErrorCallback({source:"update",message:`Error processing update of "/${ref.path}"`,details:err})}))}),processPromise);await processPromise};let syncInProgress=false;const syncPromises=[];const syncCompleted=()=>{let resolve;const promise=new Promise((rs=>resolve=rs));syncPromises.push({resolve:resolve});return promise};let processQueueTimeout=null;const scheduleSync=()=>{if(!processQueueTimeout){processQueueTimeout=setTimeout((async()=>{syncInProgress=true;processQueueTimeout=null;await pushLocalMutations();syncInProgress=false;syncPromises.splice(0).forEach((p=>p.resolve()))}),0)}};const flagOverwritten=target=>{if(!mutationQueue.find((m=>RelativeNodeTarget.areEqual(m.target,target)))){mutationQueue.push({target:target,previous:utils_1.cloneObject(getTargetValue(cache,target))})}scheduleSync()};const localMutationsEmitter=new simple_event_emitter_1.SimpleEventEmitter;const addOnChangeHandler=(target,callback)=>{const isObject=val=>val!==null&&typeof val==="object";const mutationsHandler=async details=>{var _a;const{snap:snap,origin:origin}=details;const context=snap.context();const causedByOurProxy=((_a=context.acebase_proxy)===null||_a===void 0?void 0:_a.id)===proxyId;if(details.origin==="remote"&&causedByOurProxy){console.error("DEV ISSUE: mutationsHandler was called from remote event originating from our own proxy");return}const mutations=snap.val(false).filter((mutation=>mutation.target.slice(0,target.length).every(((key,i)=>target[i]===key))));if(mutations.length===0){return}let newValue,previousValue;const singleMutation=mutations.find((m=>m.target.length<=target.length));if(singleMutation){const trailKeys=target.slice(singleMutation.target.length);newValue=trailKeys.reduce(((val,key)=>!isObject(val)||!(key in val)?null:val[key]),singleMutation.val);previousValue=trailKeys.reduce(((val,key)=>!isObject(val)||!(key in val)?null:val[key]),singleMutation.prev)}else{const currentValue=getTargetValue(cache,target);newValue=utils_1.cloneObject(currentValue);previousValue=utils_1.cloneObject(newValue);mutations.forEach((mutation=>{const trailKeys=mutation.target.slice(target.length);for(let i=0,val=newValue,prev=previousValue;i<trailKeys.length;i++){const last=i+1===trailKeys.length,key=trailKeys[i];if(last){val[key]=mutation.val;if(val[key]===null){delete val[key]}prev[key]=mutation.prev;if(prev[key]===null){delete prev[key]}}else{val=val[key]=key in val?val[key]:{};prev=prev[key]=key in prev?prev[key]:{}}}}))}process_1.default.nextTick((()=>{let keepSubscription=true;try{keepSubscription=false!==callback(Object.freeze(newValue),Object.freeze(previousValue),!causedByOurProxy,context)}catch(err){onErrorCallback({source:origin==="remote"?"remote_update":"local_update",message:`Error running subscription callback`,details:err})}if(keepSubscription===false){stop()}}))};localMutationsEmitter.on("mutations",mutationsHandler);const stop=()=>{localMutationsEmitter.off("mutations",mutationsHandler);clientSubscriptions.splice(clientSubscriptions.findIndex((cs=>cs.stop===stop)),1)};clientSubscriptions.push({target:target,stop:stop});return{stop:stop}};const handleFlag=(flag,target,args)=>{if(flag==="write"){return flagOverwritten(target)}else if(flag==="onChange"){return addOnChangeHandler(target,args.callback)}else if(flag==="subscribe"||flag==="observe"){const subscribe=subscriber=>{const currentValue=getTargetValue(cache,target);subscriber.next(currentValue);const subscription=addOnChangeHandler(target,((value,previous,isRemote,context)=>{subscriber.next(value)}));return function unsubscribe(){subscription.stop()}};if(flag==="subscribe"){return subscribe}const Observable=optional_observable_1.getObservable();return new Observable(subscribe)}else if(flag==="transaction"){const hasConflictingTransaction=transactions.some((t=>RelativeNodeTarget.areEqual(target,t.target)||RelativeNodeTarget.isAncestor(target,t.target)||RelativeNodeTarget.isDescendant(target,t.target)));if(hasConflictingTransaction){return Promise.reject(new Error("Cannot start transaction because it conflicts with another transaction"))}return new Promise((async resolve=>{const hasPendingMutations=mutationQueue.some((m=>RelativeNodeTarget.areEqual(target,m.target)||RelativeNodeTarget.isAncestor(target,m.target)));if(hasPendingMutations){if(!syncInProgress){scheduleSync()}await syncCompleted()}const tx={target:target,status:"started",transaction:null};transactions.push(tx);tx.transaction={get status(){return tx.status},get completed(){return tx.status!=="started"},get mutations(){return mutationQueue.filter((m=>RelativeNodeTarget.areEqual(tx.target,m.target)||RelativeNodeTarget.isAncestor(tx.target,m.target)))},get hasMutations(){return this.mutations.length>0},async commit(){if(this.completed){throw new Error(`Transaction has completed already (status '${tx.status}')`)}tx.status="finished";transactions.splice(transactions.indexOf(tx),1);if(syncInProgress){await syncCompleted()}scheduleSync();await syncCompleted()},rollback(){if(this.completed){throw new Error(`Transaction has completed already (status '${tx.status}')`)}tx.status="canceled";const mutations=[];for(let i=0;i<mutationQueue.length;i++){const m=mutationQueue[i];if(RelativeNodeTarget.areEqual(tx.target,m.target)||RelativeNodeTarget.isAncestor(tx.target,m.target)){mutationQueue.splice(i,1);i--;mutations.push(m)}}mutations.reverse().forEach((m=>{if(m.target.length===0){cache=m.previous}else{setTargetValue(cache,m.target,m.previous)}}));transactions.splice(transactions.indexOf(tx),1)}};resolve(tx.transaction)}))}};const snap=await ref.get({allow_cache:true});const gotOfflineStartValue=snap.context().acebase_origin==="cache";if(gotOfflineStartValue){console.warn(`Started data proxy with cached value of "${ref.path}", check if its value is reloaded on next connection!`)}loaded=true;cache=snap.val();if(cache===null&&typeof defaultValue!=="undefined"){cache=defaultValue;await ref.context({acebase_proxy:{id:proxyId,source:"defaultvalue",update_id:id_1.ID.generate()}}).set(cache)}proxy=createProxy({root:{ref:ref,get cache(){return cache}},target:[],id:proxyId,flag:handleFlag});const assertProxyAvailable=()=>{if(proxy===null){throw new Error(`Proxy was destroyed`)}};const reload=async()=>{assertProxyAvailable();mutationQueue.splice(0);const snap=await ref.get({allow_cache:false});const oldVal=cache,newVal=snap.val();cache=newVal;const mutations=utils_1.getMutations(oldVal,newVal);if(mutations.length===0){return}const context=snap.context();context.acebase_proxy={id:proxyId,source:"reload"};if(onMutationCallback){mutations.forEach((m=>{const targetRef=getTargetRef(ref,m.target);const newSnap=new data_snapshot_1.DataSnapshot(targetRef,m.val,m.val===null,m.prev,context);onMutationCallback(newSnap,true)}))}const mutationsSnap=new data_snapshot_1.MutationsDataSnapshot(ref,mutations,context);localMutationsEmitter.emit("mutations",{origin:"local",snap:mutationsSnap})};return{async destroy(){await processPromise;const promises=[subscription.stop(),...clientSubscriptions.map((cs=>cs.stop()))];await Promise.all(promises);cache=null;proxy=null},stop(){this.destroy()},get value(){assertProxyAvailable();return proxy},get hasValue(){assertProxyAvailable();return cache!==null},set value(val){assertProxyAvailable();if(val!==null&&typeof val==="object"&&val[isProxy]){val=val.valueOf()}flagOverwritten([]);cache=val},get ref(){return ref},reload:reload,onMutation(callback){assertProxyAvailable();onMutationCallback=(...args)=>{try{callback(...args)}catch(err){onErrorCallback({source:"mutation_callback",message:"Error in dataproxy onMutation callback",details:err})}}},onError(callback){assertProxyAvailable();onErrorCallback=(...args)=>{try{callback(...args)}catch(err){console.error(`Error in dataproxy onError callback: ${err.message}`)}}}}}}exports.LiveDataProxy=LiveDataProxy;function getTargetValue(obj,target){let val=obj;for(let key of target){val=typeof val==="object"&&val!==null&&key in val?val[key]:null}return val}function setTargetValue(obj,target,value){if(target.length===0){throw new Error(`Cannot update root target, caller must do that itself!`)}const targetObject=target.slice(0,-1).reduce(((obj,key)=>obj[key]),obj);const prop=target.slice(-1)[0];if(value===null||typeof value==="undefined"){targetObject instanceof Array?targetObject.splice(prop,1):delete targetObject[prop]}else{targetObject[prop]=value}}function getTargetRef(ref,target){const path=path_info_1.PathInfo.get(ref.path).childPath(target);return new data_reference_1.DataReference(ref.db,path)}function createProxy(context){const targetRef=getTargetRef(context.root.ref,context.target);const childProxies=[];const handler={get(target,prop,receiver){target=getTargetValue(context.root.cache,context.target);if(typeof prop==="symbol"){if(prop.toString()===Symbol.iterator.toString()){prop="values"}else if(prop.toString()===isProxy.toString()){return true}else{return Reflect.get(target,prop,receiver)}}if(prop==="valueOf"){return function valueOf(){return target}}if(target===null||typeof target!=="object"){throw new Error(`Cannot read property "${prop}" of ${target}. Value of path "/${targetRef.path}" is not an object (anymore)`)}if(target instanceof Array&&typeof prop==="string"&&/^[0-9]+$/.test(prop)){prop=parseInt(prop)}const value=target[prop];if(value===null){delete target[prop];return}const childProxy=childProxies.find((proxy=>proxy.prop===prop));if(childProxy){if(childProxy.typeof===typeof value){return childProxy.value}childProxies.splice(childProxies.indexOf(childProxy),1)}const proxifyChildValue=prop=>{const value=target[prop];let childProxy=childProxies.find((child=>child.prop===prop));if(childProxy){if(childProxy.typeof===typeof value){return childProxy.value}childProxies.splice(childProxies.indexOf(childProxy),1)}if(typeof value!=="object"){return value}const newChildProxy=createProxy({root:context.root,target:context.target.concat(prop),id:context.id,flag:context.flag});childProxies.push({typeof:typeof value,prop:prop,value:newChildProxy});return newChildProxy};const unproxyValue=value=>value!==null&&typeof value==="object"&&value[isProxy]?value.getTarget():value;if(["string","number","boolean"].includes(typeof value)||value instanceof Date||value instanceof path_reference_1.PathReference||value instanceof ArrayBuffer||typeof value==="object"&&"buffer"in value){return value}const isArray=target instanceof Array;if(prop==="toString"){return function toString(){return`[LiveDataProxy for "${targetRef.path}"]`}}if(typeof value==="undefined"){if(prop==="push"){return function push(item){const childRef=targetRef.push();context.flag("write",context.target.concat(childRef.key));target[childRef.key]=item;return childRef.key}}if(prop==="getTarget"){return function(warn=true){warn&&console.warn(`Use getTarget with caution - any changes will not be synchronized!`);return target}}if(prop==="getRef"){return function getRef(){const ref=getTargetRef(context.root.ref,context.target);return ref}}if(prop==="forEach"){return function forEach(callback){const keys=Object.keys(target);let stop=false;for(let i=0;!stop&&i<keys.length;i++){const key=keys[i];const value=proxifyChildValue(key);stop=callback(value,key,i)===false}}}if(["values","entries","keys"].includes(prop)){return function*generator(){const keys=Object.keys(target);for(let key of keys){if(prop==="keys"){yield key}else{const value=proxifyChildValue(key);if(prop==="entries"){yield[key,value]}else{yield value}}}}}if(prop==="toArray"){return function toArray(sortFn){const arr=Object.keys(target).map((key=>proxifyChildValue(key)));if(sortFn){arr.sort(sortFn)}return arr}}if(prop==="onChanged"){return function onChanged(callback){return context.flag("onChange",context.target,{callback:callback})}}if(prop==="subscribe"){return function subscribe(){return context.flag("subscribe",context.target)}}if(prop==="getObservable"){return function getObservable(){return context.flag("observe",context.target)}}if(prop==="getOrderedCollection"){return function getOrderedCollection(orderProperty,orderIncrement){return new OrderedCollectionProxy(this,orderProperty,orderIncrement)}}if(prop==="startTransaction"){return function startTransaction(){return context.flag("transaction",context.target)}}if(prop==="remove"&&!isArray){return function remove(){if(context.target.length===0){throw new Error(`Can't remove proxy root value`)}const parent=getTargetValue(context.root.cache,context.target.slice(0,-1));const key=context.target.slice(-1)[0];context.flag("write",context.target);delete parent[key]}}return}else if(typeof value==="function"){if(isArray){const writeArray=action=>{context.flag("write",context.target);return action()};const cleanArrayValues=values=>values.map((value=>{value=unproxyValue(value);removeVoidProperties(value);return value}));if(prop==="push"){return function push(...items){items=cleanArrayValues(items);return writeArray((()=>target.push(...items)))}}if(prop==="pop"){return function pop(){return writeArray((()=>target.pop()))}}if(prop==="splice"){return function splice(start,deleteCount,...items){items=cleanArrayValues(items);return writeArray((()=>target.splice(start,deleteCount,...items)))}}if(prop==="shift"){return function shift(){return writeArray((()=>target.shift()))}}if(prop==="unshift"){return function unshift(...items){items=cleanArrayValues(items);return writeArray((()=>target.unshift(...items)))}}if(prop==="sort"){return function sort(compareFn){return writeArray((()=>target.sort(compareFn)))}}if(prop==="reverse"){return function reverse(){return writeArray((()=>target.reverse()))}}if(["indexOf","lastIndexOf"].includes(prop)){return function indexOf(item,start){if(item!==null&&typeof item==="object"&&item[isProxy]){item=item.getTarget(false)}return target[prop](item,start)}}if(["forEach","every","some","filter","map"].includes(prop)){return function iterate(callback){return target[prop](((value,i)=>callback(proxifyChildValue(i),i,proxy)))}}if(["reduce","reduceRight"].includes(prop)){return function reduce(callback,initialValue){return target[prop](((prev,value,i)=>callback(prev,proxifyChildValue(i),i,proxy)),initialValue)}}if(["find","findIndex"].includes(prop)){return function find(callback){let value=target[prop](((value,i)=>callback(proxifyChildValue(i),i,proxy)));if(prop==="find"&&value){let index=target.indexOf(value);value=proxifyChildValue(index)}return value}}if(["values","entries","keys"].includes(prop)){return function*generator(){for(let i=0;i<target.length;i++){if(prop==="keys"){yield i}else{const value=proxifyChildValue(i);if(prop==="entries"){yield[i,value]}else{yield value}}}}}}return value}return proxifyChildValue(prop)},set(target,prop,value,receiver){target=getTargetValue(context.root.cache,context.target);if(typeof prop==="symbol"){return Reflect.set(target,prop,value,receiver)}if(target===null||typeof target!=="object"){throw new Error(`Cannot set property "${prop}" of ${target}. Value of path "/${targetRef.path}" is not an object`)}if(target instanceof Array&&typeof prop==="string"){if(!/^[0-9]+$/.test(prop)){throw new Error(`Cannot set property "${prop}" on array value of path "/${targetRef.path}"`)}prop=parseInt(prop)}if(value!==null){if(typeof value==="object"){if(value[isProxy]){value=value.valueOf()}value=utils_1.cloneObject(value)}if(utils_1.valuesAreEqual(value,target[prop])){return true}}if(context.target.some((key=>typeof key==="number"))){context.flag("write",context.target.slice(0,context.target.findIndex((key=>typeof key==="number"))))}else if(target instanceof Array){context.flag("write",context.target)}else{context.flag("write",context.target.concat(prop))}if(value===null){delete target[prop]}else{removeVoidProperties(value);target[prop]=value}return true},deleteProperty(target,prop){target=getTargetValue(context.root.cache,context.target);if(target===null){throw new Error(`Cannot delete property ${prop.toString()} of null`)}if(typeof prop==="symbol"){return Reflect.deleteProperty(target,prop)}if(!(prop in target)){return true}context.flag("write",context.target.concat(prop));delete target[prop];return true},ownKeys(target){target=getTargetValue(context.root.cache,context.target);return Reflect.ownKeys(target)},has(target,prop){target=getTargetValue(context.root.cache,context.target);return Reflect.has(target,prop)},getOwnPropertyDescriptor(target,prop){target=getTargetValue(context.root.cache,context.target);const descriptor=Reflect.getOwnPropertyDescriptor(target,prop);if(descriptor){descriptor.configurable=true}return descriptor},getPrototypeOf(target){target=getTargetValue(context.root.cache,context.target);return Reflect.getPrototypeOf(target)}};const proxy=new Proxy({},handler);return proxy}function removeVoidProperties(obj){if(typeof obj!=="object"){return}Object.keys(obj).forEach((key=>{const val=obj[key];if(val===null||typeof val==="undefined"){delete obj[key]}else if(typeof val==="object"){removeVoidProperties(val)}}))}function proxyAccess(proxiedValue){if(typeof proxiedValue!=="object"||!proxiedValue[isProxy]){throw new Error(`Given value is not proxied. Make sure you are referencing the value through the live data proxy.`)}return proxiedValue}exports.proxyAccess=proxyAccess;class OrderedCollectionProxy{constructor(collection,orderProperty="order",orderIncrement=10){this.collection=collection;this.orderProperty=orderProperty;this.orderIncrement=orderIncrement;if(typeof collection!=="object"||!collection[isProxy]){throw new Error(`Collection is not proxied`)}if(collection.valueOf()instanceof Array){throw new Error(`Collection is an array, not an object collection`)}if(!Object.keys(collection).every((key=>typeof collection[key]==="object"))){throw new Error(`Collection has non-object children`)}const ok=Object.keys(collection).every((key=>typeof collection[key][orderProperty]==="number"));if(!ok){const keys=Object.keys(collection);for(let i=0;i<keys.length;i++){const item=collection[keys[i]];item[orderProperty]=i*orderIncrement}}}getObservable(){return proxyAccess(this.collection).getObservable()}getArrayObservable(){const Observable=optional_observable_1.getObservable();return new Observable((subscriber=>{const subscription=this.getObservable().subscribe((value=>{const newArray=this.getArray();subscriber.next(newArray)}));return function unsubscribe(){subscription.unsubscribe()}}))}getArray(){const arr=proxyAccess(this.collection).toArray(((a,b)=>a[this.orderProperty]-b[this.orderProperty]));return arr}add(item,index,from){let arr=this.getArray();let minOrder=Number.POSITIVE_INFINITY,maxOrder=Number.NEGATIVE_INFINITY;for(let i=0;i<arr.length;i++){const order=arr[i][this.orderProperty];minOrder=Math.min(order,minOrder);maxOrder=Math.max(order,maxOrder)}let fromKey;if(typeof from==="number"){fromKey=Object.keys(this.collection).find((key=>this.collection[key]===item));if(!fromKey){throw new Error(`item not found in collection`)}if(from===index){return{key:fromKey,index:index}}if(Math.abs(from-index)===1){const otherItem=arr[index];const otherOrder=otherItem[this.orderProperty];otherItem[this.orderProperty]=item[this.orderProperty];item[this.orderProperty]=otherOrder;return{key:fromKey,index:index}}else{arr.splice(from,1)}}if(typeof index!=="number"||index>=arr.length){index=arr.length;item[this.orderProperty]=arr.length==0?0:maxOrder+this.orderIncrement}else if(index===0){item[this.orderProperty]=arr.length==0?0:minOrder-this.orderIncrement}else{const orders=arr.map((item=>item[this.orderProperty]));const gap=orders[index]-orders[index-1];if(gap>1){item[this.orderProperty]=orders[index]-Math.floor(gap/2)}else{arr.splice(index,0,item);for(let i=0;i<arr.length;i++){arr[i][this.orderProperty]=i*this.orderIncrement}}}const key=typeof fromKey==="string"?fromKey:proxyAccess(this.collection).push(item);return{key:key,index:index}}delete(index){const arr=this.getArray();const item=arr[index];if(!item){throw new Error(`Item at index ${index} not found`)}const key=Object.keys(this.collection).find((key=>this.collection[key]===item));if(!key){throw new Error(`Cannot find target object to delete`)}this.collection[key]=null;return{key:key,index:index}}move(fromIndex,toIndex){const arr=this.getArray();return this.add(arr[fromIndex],toIndex,fromIndex)}sort(sortFn){const arr=this.getArray();arr.sort(sortFn);for(let i=0;i<arr.length;i++){arr[i][this.orderProperty]=i*this.orderIncrement}}}exports.OrderedCollectionProxy=OrderedCollectionProxy},{"./data-reference":8,"./data-snapshot":9,"./id":11,"./optional-observable":14,"./path-info":16,"./path-reference":17,"./process":18,"./simple-event-emitter":22,"./utils":26}],8:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DataReferencesArray=exports.DataSnapshotsArray=exports.DataReferenceQuery=exports.DataReference=exports.QueryDataRetrievalOptions=exports.DataRetrievalOptions=void 0;const data_snapshot_1=require("./data-snapshot");const subscription_1=require("./subscription");const id_1=require("./id");const path_info_1=require("./path-info");const data_proxy_1=require("./data-proxy");const optional_observable_1=require("./optional-observable");class DataRetrievalOptions{constructor(options){if(!options){options={}}if(typeof options.include!=="undefined"&&!(options.include instanceof Array)){throw new TypeError(`options.include must be an array`)}if(typeof options.exclude!=="undefined"&&!(options.exclude instanceof Array)){throw new TypeError(`options.exclude must be an array`)}if(typeof options.child_objects!=="undefined"&&typeof options.child_objects!=="boolean"){throw new TypeError(`options.child_objects must be a boolean`)}if(typeof options.cache_mode==="string"&&!["allow","bypass","force"].includes(options.cache_mode)){throw new TypeError(`invalid value for options.cache_mode`)}this.include=options.include||undefined;this.exclude=options.exclude||undefined;this.child_objects=typeof options.child_objects==="boolean"?options.child_objects:undefined;this.cache_mode=typeof options.cache_mode==="string"?options.cache_mode:typeof options.allow_cache==="boolean"?options.allow_cache?"allow":"bypass":"allow"}}exports.DataRetrievalOptions=DataRetrievalOptions;class QueryDataRetrievalOptions extends DataRetrievalOptions{constructor(options){super(options);if(!["undefined","boolean"].includes(typeof options.snapshots)){throw new TypeError(`options.snapshots must be a boolean`)}this.snapshots=typeof options.snapshots==="boolean"?options.snapshots:true}}exports.QueryDataRetrievalOptions=QueryDataRetrievalOptions;const _private=Symbol("private");class DataReference{constructor(db,path,vars){if(!path){path=""}path=path.replace(/^\/|\/$/g,"");const pathInfo=path_info_1.PathInfo.get(path);const key=pathInfo.key;const callbacks=[];this[_private]={get path(){return path},get key(){return key},get callbacks(){return callbacks},vars:vars||{},context:{},pushed:false};this.db=db}context(context=undefined,merge=false){const currentContext=this[_private].context;if(typeof context==="object"){const newContext=context?merge?currentContext||{}:context:{};if(context){Object.keys(context).forEach((key=>{newContext[key]=context[key]}))}this[_private].context=newContext;return this}else if(typeof context==="undefined"){console.warn(`Use snap.context() instead of snap.ref.context() to get updating context in event callbacks`);return currentContext}else{throw new Error("Invalid context argument")}}get path(){return this[_private].path}get key(){return this[_private].key}get parent(){let currentPath=path_info_1.PathInfo.fillVariables2(this.path,this.vars);const info=path_info_1.PathInfo.get(currentPath);if(info.parentPath===null){return null}return new DataReference(this.db,info.parentPath).context(this[_private].context)}get vars(){return this[_private].vars}child(childPath){childPath=typeof childPath==="number"?childPath:childPath.replace(/^\/|\/$/g,"");const currentPath=path_info_1.PathInfo.fillVariables2(this.path,this.vars);const targetPath=path_info_1.PathInfo.getChildPath(currentPath,childPath);return new DataReference(this.db,targetPath).context(this[_private].context)}async set(value,onComplete){try{if(this.isWildcardPath){throw new Error(`Cannot set the value of wildcard path "/${this.path}"`)}if(this.parent===null){throw new Error(`Cannot set the root object. Use update, or set individual child properties`)}if(typeof value==="undefined"){throw new TypeError(`Cannot store undefined value in "/${this.path}"`)}if(!this.db.isReady){await this.db.ready()}value=this.db.types.serialize(this.path,value);await this.db.api.set(this.path,value,{context:this[_private].context});if(typeof onComplete==="function"){try{onComplete(null,this)}catch(err){console.error(`Error in onComplete callback:`,err)}}}catch(err){if(typeof onComplete==="function"){try{onComplete(err,this)}catch(err){console.error(`Error in onComplete callback:`,err)}}else{throw err}}return this}async update(updates,onComplete){try{if(this.isWildcardPath){throw new Error(`Cannot update the value of wildcard path "/${this.path}"`)}if(!this.db.isReady){await this.db.ready()}if(typeof updates!=="object"||updates instanceof Array||updates instanceof ArrayBuffer||updates instanceof Date){await this.set(updates)}else if(Object.keys(updates).length===0){console.warn(`update called on path "/${this.path}", but there is nothing to update`)}else{updates=this.db.types.serialize(this.path,updates);await this.db.api.update(this.path,updates,{context:this[_private].context})}if(typeof onComplete==="function"){try{onComplete(null,this)}catch(err){console.error(`Error in onComplete callback:`,err)}}}catch(err){if(typeof onComplete==="function"){try{onComplete(err,this)}catch(err){console.error(`Error in onComplete callback:`,err)}}else{throw err}}return this}async transaction(callback){if(this.isWildcardPath){throw new Error(`Cannot start a transaction on wildcard path "/${this.path}"`)}if(!this.db.isReady){await this.db.ready()}let throwError;let cb=currentValue=>{currentValue=this.db.types.deserialize(this.path,currentValue);const snap=new data_snapshot_1.DataSnapshot(this,currentValue);let newValue;try{newValue=callback(snap)}catch(err){throwError=err;return}if(newValue instanceof Promise){return newValue.then((val=>this.db.types.serialize(this.path,val))).catch((err=>{throwError=err;return}))}else{return this.db.types.serialize(this.path,newValue)}};const result=await this.db.api.transaction(this.path,cb,{context:this[_private].context});if(throwError){throw throwError}return this}on(event,callback,cancelCallback){if(this.path===""&&["value","child_changed"].includes(event)){console.warn(`WARNING: Listening for value and child_changed events on the root node is a bad practice. These events require loading of all data (value event), or potentially lots of data (child_changed event) each time they are fired`)}let eventPublisher=null;const eventStream=new subscription_1.EventStream((publisher=>{eventPublisher=publisher}));const cb={event:event,stream:eventStream,userCallback:typeof callback==="function"&&callback,ourCallback:(err,path,newValue,oldValue,eventContext)=>{if(err){this.db.debug.error(`Error getting data for event ${event} on path "${path}"`,err);return}let ref=this.db.ref(path);ref[_private].vars=path_info_1.PathInfo.extractVariables(this.path,path);let callbackObject;if(event.startsWith("notify_")){callbackObject=ref.context(eventContext||{})}else{const values={previous:this.db.types.deserialize(path,oldValue),current:this.db.types.deserialize(path,newValue)};if(event==="child_removed"){callbackObject=new data_snapshot_1.DataSnapshot(ref,values.previous,true,values.previous,eventContext)}else if(event==="mutations"){callbackObject=new data_snapshot_1.MutationsDataSnapshot(ref,values.current,eventContext)}else{const isRemoved=event==="mutated"&&values.current===null;callbackObject=new data_snapshot_1.DataSnapshot(ref,values.current,isRemoved,values.previous,eventContext)}}eventPublisher.publish(callbackObject)}};this[_private].callbacks.push(cb);const subscribe=()=>{if(typeof callback==="function"){eventStream.subscribe(callback,((activated,cancelReason)=>{if(!activated){cancelCallback&&cancelCallback(cancelReason)}}))}const advancedOptions=typeof callback==="object"?callback:{newOnly:!callback};if(typeof advancedOptions.newOnly!=="boolean"){advancedOptions.newOnly=false}if(this.isWildcardPath){advancedOptions.newOnly=true}const cancelSubscription=err=>{let callbacks=this[_private].callbacks;callbacks.splice(callbacks.indexOf(cb),1);this.db.api.unsubscribe(this.path,event,cb.ourCallback);eventPublisher.cancel(err.message)};let authorized=this.db.api.subscribe(this.path,event,cb.ourCallback,{newOnly:advancedOptions.newOnly,cancelCallback:cancelSubscription,syncFallback:advancedOptions.syncFallback});const allSubscriptionsStoppedCallback=()=>{let callbacks=this[_private].callbacks;callbacks.splice(callbacks.indexOf(cb),1);return this.db.api.unsubscribe(this.path,event,cb.ourCallback)};if(authorized instanceof Promise){authorized.then((()=>{eventPublisher.start(allSubscriptionsStoppedCallback)})).catch(cancelSubscription)}else{eventPublisher.start(allSubscriptionsStoppedCallback)}if(!advancedOptions.newOnly){if(event==="value"){this.get((snap=>{eventPublisher.publish(snap)}))}else if(event==="child_added"){this.get((snap=>{const val=snap.val();if(val===null||typeof val!=="object"){return}Object.keys(val).forEach((key=>{let childSnap=new data_snapshot_1.DataSnapshot(this.child(key),val[key]);eventPublisher.publish(childSnap)}))}))}else if(event==="notify_child_added"){const step=100;let limit=step,skip=0;const more=()=>{this.db.api.reflect(this.path,"children",{limit:limit,skip:skip}).then((children=>{children.list.forEach((child=>{const childRef=this.child(child.key);eventPublisher.publish(childRef)}));if(children.more){skip+=step;more()}}))};more()}}};if(this.db.isReady){subscribe()}else{this.db.ready(subscribe)}return eventStream}off(event,callback){const subscriptions=this[_private].callbacks;const stopSubs=subscriptions.filter((sub=>(!event||sub.event===event)&&(!callback||sub.userCallback===callback)));if(stopSubs.length===0){this.db.debug.warn(`Can't find event subscriptions to stop (path: "${this.path}", event: ${event||"(any)"}, callback: ${callback})`)}stopSubs.forEach((sub=>{sub.stream.stop()}));return this}get(optionsOrCallback,callback){if(!this.db.isReady){const promise=this.db.ready().then((()=>this.get(optionsOrCallback,callback)));return typeof optionsOrCallback!=="function"&&typeof callback!=="function"?promise:undefined}callback=typeof optionsOrCallback==="function"?optionsOrCallback:typeof callback==="function"?callback:undefined;if(this.isWildcardPath){const error=new Error(`Cannot get value of wildcard path "/${this.path}". Use .query() instead`);if(typeof callback==="function"){throw error}return Promise.reject(error)}const options=new DataRetrievalOptions(typeof optionsOrCallback==="object"?optionsOrCallback:{cache_mode:"allow"});const promise=this.db.api.get(this.path,options).then((result=>{const isNewApiResult="context"in result&&"value"in result;if(!isNewApiResult){console.warn(`AceBase api.get method returned an old response value. Update your acebase or acebase-client package`);result={value:result,context:{}}}const value=this.db.types.deserialize(this.path,result.value);const snapshot=new data_snapshot_1.DataSnapshot(this,value,undefined,undefined,result.context);return snapshot}));if(callback){promise.then(callback).catch((err=>{console.error(`Uncaught error:`,err)}));return}else{return promise}}once(event,options){if(event==="value"&&!this.isWildcardPath){return this.get(options)}return new Promise(((resolve,reject)=>{const callback=snap=>{this.off(event,callback);resolve(snap)};this.on(event,callback)}))}push(value,onComplete){if(this.isWildcardPath){const error=new Error(`Cannot push to wildcard path "/${this.path}"`);if(typeof value==="undefined"||typeof onComplete==="function"){throw error}return Promise.reject(error)}const id=id_1.ID.generate();const ref=this.child(id);ref[_private].pushed=true;if(typeof value!=="undefined"){return ref.set(value,onComplete).then((res=>ref))}else{return ref}}async remove(){if(this.isWildcardPath){throw new Error(`Cannot remove wildcard path "/${this.path}". Use query().remove instead`)}if(this.parent===null){throw new Error(`Cannot remove the root node`)}return this.set(null)}async exists(){if(this.isWildcardPath){throw new Error(`Cannot check wildcard path "/${this.path}" existence`)}if(!this.db.isReady){await this.db.ready()}return this.db.api.exists(this.path)}get isWildcardPath(){return this.path.indexOf("*")>=0||this.path.indexOf("$")>=0}query(){return new DataReferenceQuery(this)}async count(){const info=await this.reflect("info",{child_count:true});return info.children.count}async reflect(type,args){if(this.isWildcardPath){throw new Error(`Cannot reflect on wildcard path "/${this.path}"`)}if(!this.db.isReady){await this.db.ready()}return this.db.api.reflect(this.path,type,args)}async export(write,options={format:"json",type_safe:true}){if(this.isWildcardPath){throw new Error(`Cannot export wildcard path "/${this.path}"`)}if(!this.db.isReady){await this.db.ready()}return this.db.api.export(this.path,write,options)}async import(read,options={format:"json",suppress_events:false}){if(this.isWildcardPath){throw new Error(`Cannot import to wildcard path "/${this.path}"`)}if(!this.db.isReady){await this.db.ready()}return this.db.api.import(this.path,read,options)}proxy(defaultValue){return data_proxy_1.LiveDataProxy.create(this,defaultValue)}observe(options){if(options){throw new Error("observe does not support data retrieval options yet")}if(this.isWildcardPath){throw new Error(`Cannot observe wildcard path "/${this.path}"`)}const Observable=optional_observable_1.getObservable();return new Observable((observer=>{let cache,resolved=false;let promise=this.get(options).then((snap=>{resolved=true;cache=snap.val();observer.next(cache)}));const updateCache=snap=>{if(!resolved){promise=promise.then((()=>updateCache(snap)));return}const mutatedPath=snap.ref.path;if(mutatedPath===this.path){cache=snap.val();return observer.next(cache)}const trailKeys=path_info_1.PathInfo.getPathKeys(mutatedPath).slice(path_info_1.PathInfo.getPathKeys(this.path).length);let target=cache;while(trailKeys.length>1){const key=trailKeys.shift();if(!(key in target)){target[key]=typeof trailKeys[0]==="number"?[]:{}}target=target[key]}const prop=trailKeys.shift();const newValue=snap.val();if(newValue===null){target instanceof Array&&typeof prop==="number"?target.splice(prop,1):delete target[prop]}else{target[prop]=newValue}observer.next(cache)};this.on("mutated",updateCache);return()=>{this.off("mutated",updateCache)}}))}async forEach(callbackOrOptions,callback){let options;if(typeof callbackOrOptions==="function"){callback=callbackOrOptions}else{options=callbackOrOptions}if(typeof callback!=="function"){throw new TypeError(`No callback function given`)}const info=await this.reflect("children",{limit:0,skip:0});const summary={canceled:false,total:info.list.length,processed:0};for(let i=0;i<info.list.length;i++){const key=info.list[i].key;const snapshot=await this.child(key).get(options);summary.processed++;if(!snapshot.exists()){continue}const result=await callback(snapshot);if(result===false){summary.canceled=true;break}}return summary}async getMutations(cursorOrDate){const cursor=typeof cursorOrDate==="string"?cursorOrDate:undefined;const timestamp=cursorOrDate===null||typeof cursorOrDate==="undefined"?0:cursorOrDate instanceof Date?cursorOrDate.getTime():undefined;return this.db.api.getMutations({path:this.path,cursor:cursor,timestamp:timestamp})}async getChanges(cursorOrDate){const cursor=typeof cursorOrDate==="string"?cursorOrDate:undefined;const timestamp=cursorOrDate===null||typeof cursorOrDate==="undefined"?0:cursorOrDate instanceof Date?cursorOrDate.getTime():undefined;return this.db.api.getChanges({path:this.path,cursor:cursor,timestamp:timestamp})}}exports.DataReference=DataReference;class DataReferenceQuery{constructor(ref){this.ref=ref;this[_private]={filters:[],skip:0,take:0,order:[],events:{}}}filter(key,op,compare){if((op==="in"||op==="!in")&&(!(compare instanceof Array)||compare.length===0)){throw new Error(`${op} filter for ${key} must supply an Array compare argument containing at least 1 value`)}if((op==="between"||op==="!between")&&(!(compare instanceof Array)||compare.length!==2)){throw new Error(`${op} filter for ${key} must supply an Array compare argument containing 2 values`)}if((op==="matches"||op==="!matches")&&!(compare instanceof RegExp)){throw new Error(`${op} filter for ${key} must supply a RegExp compare argument`)}if((op==="contains"||op==="!contains")&&(typeof compare==="object"&&!(compare instanceof Array)&&!(compare instanceof Date)||compare instanceof Array&&compare.length===0)){throw new Error(`${op} filter for ${key} must supply a simple value or (non-zero length) array compare argument`)}this[_private].filters.push({key:key,op:op,compare:compare});return this}where(key,op,compare){return this.filter(key,op,compare)}take(n){this[_private].take=n;return this}skip(n){this[_private].skip=n;return this}sort(key,ascending=true){if(!["string","number"].includes(typeof key)){throw`key must be a string or number`}this[_private].order.push({key:key,ascending:ascending});return this}order(key,ascending=true){return this.sort(key,ascending)}get(optionsOrCallback,callback){if(!this.ref.db.isReady){const promise=this.ref.db.ready().then((()=>this.get(optionsOrCallback,callback)));return typeof optionsOrCallback!=="function"&&typeof callback!=="function"?promise:undefined}callback=typeof optionsOrCallback==="function"?optionsOrCallback:typeof callback==="function"?callback:undefined;const options=new QueryDataRetrievalOptions(typeof optionsOrCallback==="object"?optionsOrCallback:{snapshots:true,cache_mode:"allow"});options.allow_cache=options.cache_mode!=="bypass";options.eventHandler=ev=>{if(!this[_private].events[ev.name]){return false}const listeners=this[_private].events[ev.name];if(typeof listeners!=="object"||listeners.length===0){return false}if(["add","change","remove"].includes(ev.name)){const ref=new DataReference(this.ref.db,ev.path);const eventData={name:ev.name};if(options.snapshots&&ev.name!=="remove"){const val=db.types.deserialize(ev.path,ev.value);eventData.snapshot=new data_snapshot_1.DataSnapshot(ref,val,false)}else{eventData.ref=ref}ev=eventData}listeners.forEach((callback=>{try{callback(ev)}catch(e){}}))};options.monitor={add:false,change:false,remove:false};if(this[_private].events){if(this[_private].events["add"]&&this[_private].events["add"].length>0){options.monitor.add=true}if(this[_private].events["change"]&&this[_private].events["change"].length>0){options.monitor.change=true}if(this[_private].events["remove"]&&this[_private].events["remove"].length>0){options.monitor.remove=true}}const db=this.ref.db;return db.api.query(this.ref.path,this[_private],options).catch((err=>{throw new Error(err)})).then((res=>{let{results:results,context:context}=res;if(!("results"in res&&"context"in res)){console.warn(`Query results missing context. Update your acebase and/or acebase-client packages`);results=res,context={}}if(options.snapshots){const snaps=results.map((result=>{const val=db.types.deserialize(result.path,result.val);return new data_snapshot_1.DataSnapshot(db.ref(result.path),val,false,undefined,context)}));return DataSnapshotsArray.from(snaps)}else{const refs=results.map((path=>db.ref(path)));return DataReferencesArray.from(refs)}})).then((results=>{callback&&callback(results);return results}))}getRefs(callback){return this.get({snapshots:false},callback)}find(){return this.get({snapshots:false})}count(){return this.get({snapshots:false}).then((refs=>refs.length))}exists(){return this.count().then((count=>count>0))}remove(callback){const promise=this.get({snapshots:false}).then((refs=>Promise.all(refs.map((ref=>ref.remove().then((()=>({success:true,ref:ref}))).catch((err=>({success:false,error:err,ref:ref})))))).then((results=>{callback&&callback(results);return results}))));if(!callback){return promise}}on(event,callback){if(!this[_private].events[event]){this[_private].events[event]=[]}this[_private].events[event].push(callback);return this}off(event,callback){if(typeof event==="undefined"){this[_private].events={};return this}if(!this[_private].events[event]){return this}if(typeof callback==="undefined"){delete this[_private].events[event];return this}const index=this[_private].events[event].indexOf(callback);if(!~index){return this}this[_private].events[event].splice(index,1);return this}async forEach(callbackOrOptions,callback){let options;if(typeof callbackOrOptions==="function"){callback=callbackOrOptions}else{options=callbackOrOptions}if(typeof callback!=="function"){throw new TypeError(`No callback function given`)}const refs=await this.getRefs();const summary={canceled:false,total:refs.length,processed:0};for(let i=0;i<refs.length;i++){const ref=refs[i];const snapshot=await ref.get(options);summary.processed++;if(!snapshot.exists()){continue}const result=await callback(snapshot);if(result===false){summary.canceled=true;break}}return summary}}exports.DataReferenceQuery=DataReferenceQuery;class DataSnapshotsArray extends Array{static from(snaps){const arr=new DataSnapshotsArray(snaps.length);snaps.forEach(((snap,i)=>arr[i]=snap));return arr}getValues(){return this.map((snap=>snap.val()))}}exports.DataSnapshotsArray=DataSnapshotsArray;class DataReferencesArray extends Array{static from(refs){const arr=new DataReferencesArray(refs.length);refs.forEach(((ref,i)=>arr[i]=ref));return arr}getPaths(){return this.map((ref=>ref.path))}}exports.DataReferencesArray=DataReferencesArray},{"./data-proxy":7,"./data-snapshot":9,"./id":11,"./optional-observable":14,"./path-info":16,"./subscription":23}],9:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.MutationsDataSnapshot=exports.DataSnapshot=void 0;const path_info_1=require("./path-info");function getChild(snapshot,path,previous=false){if(!snapshot.exists()){return null}let child=previous?snapshot.previous():snapshot.val();if(typeof path==="number"){return child[path]}path_info_1.PathInfo.getPathKeys(path).every((key=>{child=child[key];return typeof child!=="undefined"}));return child||null}function getChildren(snapshot){if(!snapshot.exists()){return[]}let value=snapshot.val();if(value instanceof Array){return new Array(value.length).map(((v,i)=>i))}if(typeof value==="object"){return Object.keys(value)}return[]}class DataSnapshot{constructor(ref,value,isRemoved=false,prevValue,context){this.ref=ref;this.val=()=>value;this.previous=()=>prevValue;this.exists=()=>{if(isRemoved){return false}return value!==null&&typeof value!=="undefined"};this.context=()=>context||{}}val(){}previous(){}exists(){return false}context(){}static for(ref,value){return new DataSnapshot(ref,value)}child(path){let val=getChild(this,path,false);let prev=getChild(this,path,true);return new DataSnapshot(this.ref.child(path),val,false,prev)}hasChild(path){return getChild(this,path)!==null}hasChildren(){return getChildren(this).length>0}numChildren(){return getChildren(this).length}forEach(callback){const value=this.val();const prev=this.previous();return getChildren(this).every(((key,i)=>{const snap=new DataSnapshot(this.ref.child(key),value[key],false,prev[key]);return callback(snap)}))}get key(){return this.ref.key}}exports.DataSnapshot=DataSnapshot;class MutationsDataSnapshot extends DataSnapshot{val(warn=true){return[]}previous(){throw new Error("Iterate values to get previous values for each mutation")}constructor(ref,mutations,context){super(ref,mutations,false,undefined,context);this.val=(warn=true)=>{if(warn){console.warn(`Unless you know what you are doing, it is best not to use the value of a mutations snapshot directly. Use child methods and forEach to iterate the mutations instead`)}return mutations}}forEach(callback){const mutations=this.val();return mutations.every((mutation=>{const ref=mutation.target.reduce(((ref,key)=>ref.child(key)),this.ref);const snap=new DataSnapshot(ref,mutation.val,false,mutation.prev);return callback(snap)}))}child(index){if(typeof index!=="number"){throw new Error(`child index must be a number`)}const mutation=this.val()[index];const ref=mutation.target.reduce(((ref,key)=>ref.child(key)),this.ref);return new DataSnapshot(ref,mutation.val,false,mutation.prev)}}exports.MutationsDataSnapshot=MutationsDataSnapshot},{"./path-info":16}],10:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DebugLogger=void 0;const process_1=require("./process");class DebugLogger{constructor(level="log",prefix=""){this.prefix=prefix;this.setLevel(level)}setLevel(level){const prefix=this.prefix?this.prefix+" %s":"";this.level=level;this.verbose=["verbose"].includes(level)?prefix?console.log.bind(console,prefix):console.log.bind(console):()=>{};this.log=["verbose","log"].includes(level)?prefix?console.log.bind(console,prefix):console.log.bind(console):()=>{};this.warn=["verbose","log","warn"].includes(level)?prefix?console.warn.bind(console,prefix):console.warn.bind(console):()=>{};this.error=["verbose","log","warn","error"].includes(level)?prefix?console.error.bind(console,prefix):console.error.bind(console):()=>{};this.write=text=>{const isRunKit=typeof process_1.default!=="undefined"&&process_1.default.env&&typeof process_1.default.env.RUNKIT_ENDPOINT_PATH==="string";if(text&&isRunKit){text.split("\n").forEach((line=>console.log(line)))}else{console.log(text)}}}}exports.DebugLogger=DebugLogger},{"./process":18}],11:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ID=void 0;const cuid_1=require("./cuid");let timeBias=0;class ID{static set timeBias(bias){if(typeof bias!=="number"){return}timeBias=bias}static generate(){return cuid_1.default(timeBias).slice(1)}}exports.ID=ID},{"./cuid":5}],12:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PartialArray=exports.ObjectCollection=exports.SchemaDefinition=exports.Colorize=exports.ColorStyle=exports.SimpleEventEmitter=exports.proxyAccess=exports.SimpleCache=exports.ascii85=exports.PathInfo=exports.Utils=exports.TypeMappings=exports.Transport=exports.EventSubscription=exports.EventPublisher=exports.EventStream=exports.PathReference=exports.ID=exports.DebugLogger=exports.MutationsDataSnapshot=exports.DataSnapshot=exports.DataReferencesArray=exports.DataSnapshotsArray=exports.QueryDataRetrievalOptions=exports.DataRetrievalOptions=exports.DataReferenceQuery=exports.DataReference=exports.Api=exports.AceBaseBaseSettings=exports.AceBaseBase=void 0;var acebase_base_1=require("./acebase-base");Object.defineProperty(exports,"AceBaseBase",{enumerable:true,get:function(){return acebase_base_1.AceBaseBase}});Object.defineProperty(exports,"AceBaseBaseSettings",{enumerable:true,get:function(){return acebase_base_1.AceBaseBaseSettings}});var api_1=require("./api");Object.defineProperty(exports,"Api",{enumerable:true,get:function(){return api_1.Api}});var data_reference_1=require("./data-reference");Object.defineProperty(exports,"DataReference",{enumerable:true,get:function(){return data_reference_1.DataReference}});Object.defineProperty(exports,"DataReferenceQuery",{enumerable:true,get:function(){return data_reference_1.DataReferenceQuery}});Object.defineProperty(exports,"DataRetrievalOptions",{enumerable:true,get:function(){return data_reference_1.DataRetrievalOptions}});Object.defineProperty(exports,"QueryDataRetrievalOptions",{enumerable:true,get:function(){return data_reference_1.QueryDataRetrievalOptions}});Object.defineProperty(exports,"DataSnapshotsArray",{enumerable:true,get:function(){return data_reference_1.DataSnapshotsArray}});Object.defineProperty(exports,"DataReferencesArray",{enumerable:true,get:function(){return data_reference_1.DataReferencesArray}});var data_snapshot_1=require("./data-snapshot");Object.defineProperty(exports,"DataSnapshot",{enumerable:true,get:function(){return data_snapshot_1.DataSnapshot}});Object.defineProperty(exports,"MutationsDataSnapshot",{enumerable:true,get:function(){return data_snapshot_1.MutationsDataSnapshot}});var debug_1=require("./debug");Object.defineProperty(exports,"DebugLogger",{enumerable:true,get:function(){return debug_1.DebugLogger}});var id_1=require("./id");Object.defineProperty(exports,"ID",{enumerable:true,get:function(){return id_1.ID}});var path_reference_1=require("./path-reference");Object.defineProperty(exports,"PathReference",{enumerable:true,get:function(){return path_reference_1.PathReference}});var subscription_1=require("./subscription");Object.defineProperty(exports,"EventStream",{enumerable:true,get:function(){return subscription_1.EventStream}});Object.defineProperty(exports,"EventPublisher",{enumerable:true,get:function(){return subscription_1.EventPublisher}});Object.defineProperty(exports,"EventSubscription",{enumerable:true,get:function(){return subscription_1.EventSubscription}});var transport_1=require("./transport");Object.defineProperty(exports,"Transport",{enumerable:true,get:function(){return transport_1.Transport}});var type_mappings_1=require("./type-mappings");Object.defineProperty(exports,"TypeMappings",{enumerable:true,get:function(){return type_mappings_1.TypeMappings}});exports.Utils=require("./utils");var path_info_1=require("./path-info");Object.defineProperty(exports,"PathInfo",{enumerable:true,get:function(){return path_info_1.PathInfo}});var ascii85_1=require("./ascii85");Object.defineProperty(exports,"ascii85",{enumerable:true,get:function(){return ascii85_1.ascii85}});var simple_cache_1=require("./simple-cache");Object.defineProperty(exports,"SimpleCache",{enumerable:true,get:function(){return simple_cache_1.SimpleCache}});var data_proxy_1=require("./data-proxy");Object.defineProperty(exports,"proxyAccess",{enumerable:true,get:function(){return data_proxy_1.proxyAccess}});var simple_event_emitter_1=require("./simple-event-emitter");Object.defineProperty(exports,"SimpleEventEmitter",{enumerable:true,get:function(){return simple_event_emitter_1.SimpleEventEmitter}});var simple_colors_1=require("./simple-colors");Object.defineProperty(exports,"ColorStyle",{enumerable:true,get:function(){return simple_colors_1.ColorStyle}});Object.defineProperty(exports,"Colorize",{enumerable:true,get:function(){return simple_colors_1.Colorize}});var schema_1=require("./schema");Object.defineProperty(exports,"SchemaDefinition",{enumerable:true,get:function(){return schema_1.SchemaDefinition}});var object_collection_1=require("./object-collection");Object.defineProperty(exports,"ObjectCollection",{enumerable:true,get:function(){return object_collection_1.ObjectCollection}});var partial_array_1=require("./partial-array");Object.defineProperty(exports,"PartialArray",{enumerable:true,get:function(){return partial_array_1.PartialArray}})},{"./acebase-base":1,"./api":2,"./ascii85":3,"./data-proxy":7,"./data-reference":8,"./data-snapshot":9,"./debug":10,"./id":11,"./object-collection":13,"./partial-array":15,"./path-info":16,"./path-reference":17,"./schema":19,"./simple-cache":20,"./simple-colors":21,"./simple-event-emitter":22,"./subscription":23,"./transport":24,"./type-mappings":25,"./utils":26}],13:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ObjectCollection=void 0;const id_1=require("./id");class ObjectCollection{static from(array){const collection={};array.forEach((child=>{collection[id_1.ID.generate()]=child}));return collection}}exports.ObjectCollection=ObjectCollection},{"./id":11}],14:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ObservableShim=exports.setObservable=exports.getObservable=void 0;let _observable;function getObservable(){if(_observable){return _observable}if(typeof window!=="undefined"&&window.Observable){_observable=window.Observable;return _observable}try{const{Observable:Observable}=require("rxjs");if(!Observable){throw new Error("not loaded")}_observable=Observable;return Observable}catch(err){throw new Error(`RxJS Observable could not be loaded. If you are using a browser build, add it to AceBase using db.setObservable. For node.js builds, add it to your project with: npm i rxjs`)}}exports.getObservable=getObservable;function setObservable(Observable){if(Observable==="shim"){console.warn(`Using AceBase's simple Observable shim. Only use this if you know what you're doing.`);Observable=ObservableShim}_observable=Observable}exports.setObservable=setObservable;class ObservableShim{constructor(create){this._active=false;this._subscribers=[];this._create=create}subscribe(subscriber){if(!this._active){const next=value=>{this._subscribers.forEach((s=>{try{s(value)}catch(err){console.error(`Error in subscriber callback:`,err)}}))};const observer={next:next};this._cleanup=this._create(observer);this._active=true}this._subscribers.push(subscriber);const unsubscribe=()=>{this._subscribers.splice(this._subscribers.indexOf(subscriber),1);if(this._subscribers.length===0){this._active=false;this._cleanup()}};const subscription={unsubscribe:unsubscribe};return subscription}}exports.ObservableShim=ObservableShim},{rxjs:41}],15:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PartialArray=void 0;class PartialArray{constructor(sparseArray){if(sparseArray instanceof Array){for(let i=0;i<sparseArray.length;i++){if(typeof sparseArray[i]!=="undefined"){this[i]=sparseArray[i]}}}else if(sparseArray){Object.assign(this,sparseArray)}}}exports.PartialArray=PartialArray},{}],16:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PathInfo=void 0;function getPathKeys(path){path=path.replace(/\[/g,"/[").replace(/^\/+/,"").replace(/\/+$/,"");if(path.length===0){return[]}let keys=path.split("/");return keys.map((key=>key.startsWith("[")?parseInt(key.slice(1,-1)):key))}class PathInfo{constructor(path){if(typeof path==="string"){this.keys=getPathKeys(path)}else if(path instanceof Array){this.keys=path}this.path=this.keys.reduce(((path,key,i)=>i===0?`${key}`:typeof key==="string"?`${path}/${key}`:`${path}[${key}]`),"")}static get(path){return new PathInfo(path)}static getChildPath(path,childKey){return PathInfo.get(path).child(childKey).path}static getPathKeys(path){return getPathKeys(path)}get key(){return this.keys.length===0?null:this.keys.slice(-1)[0]}get parent(){if(this.keys.length==0){return null}const parentKeys=this.keys.slice(0,-1);return new PathInfo(parentKeys)}get parentPath(){return this.keys.length===0?null:this.parent.path}child(childKey){if(typeof childKey==="string"){childKey=getPathKeys(childKey)}return new PathInfo(this.keys.concat(childKey))}childPath(childKey){return this.child(childKey).path}get pathKeys(){return this.keys}static extractVariables(varPath,fullPath){if(!varPath.includes("*")&&!varPath.includes("$")){return[]}const keys=getPathKeys(varPath);const pathKeys=getPathKeys(fullPath);let count=0;const variables={get length(){return count}};keys.forEach(((key,index)=>{const pathKey=pathKeys[index];if(key==="*"){variables[count++]=pathKey}else if(typeof key==="string"&&key[0]==="$"){variables[count++]=pathKey;variables[key]=pathKey;const varName=key.slice(1);if(typeof variables[varName]==="undefined"){variables[varName]=pathKey}}}));return variables}static fillVariables(varPath,fullPath){if(varPath.indexOf("*")<0&&varPath.indexOf("$")<0){return varPath}const keys=getPathKeys(varPath);const pathKeys=getPathKeys(fullPath);let merged=keys.map(((key,index)=>{if(key===pathKeys[index]||index>=pathKeys.length){return key}else if(typeof key==="string"&&(key==="*"||key[0]==="$")){return pathKeys[index]}else{throw new Error(`Path "${fullPath}" cannot be used to fill variables of path "${varPath}" because they do not match`)}}));let mergedPath="";merged.forEach((key=>{if(typeof key==="number"){mergedPath+=`[${key}]`}else{if(mergedPath.length>0){mergedPath+="/"}mergedPath+=key}}));return mergedPath}static fillVariables2(varPath,vars){if(typeof vars!=="object"||Object.keys(vars).length===0){return varPath}let pathKeys=getPathKeys(varPath);let n=0;const targetPath=pathKeys.reduce(((path,key)=>{if(typeof key==="string"&&(key==="*"||key.startsWith("$"))){return PathInfo.getChildPath(path,vars[n++])}else{return PathInfo.getChildPath(path,key)}}),"");return targetPath}equals(otherPath){const other=otherPath instanceof PathInfo?otherPath:new PathInfo(otherPath);if(this.path===other.path){return true}if(this.keys.length!==other.keys.length){return false}return this.keys.every(((key,index)=>{const otherKey=other.keys[index];return otherKey===key||typeof otherKey==="string"&&(otherKey==="*"||otherKey[0]==="$")||typeof key==="string"&&(key==="*"||key[0]==="$")}))}isAncestorOf(descendantPath){const descendant=descendantPath instanceof PathInfo?descendantPath:new PathInfo(descendantPath);if(descendant.path===""||this.path===descendant.path){return false}if(this.path===""){return true}if(this.keys.length>=descendant.keys.length){return false}return this.keys.every(((key,index)=>{const otherKey=descendant.keys[index];return otherKey===key||typeof otherKey==="string"&&(otherKey==="*"||otherKey[0]==="$")||typeof key==="string"&&(key==="*"||key[0]==="$")}))}isDescendantOf(ancestorPath){const ancestor=ancestorPath instanceof PathInfo?ancestorPath:new PathInfo(ancestorPath);if(this.path===""||this.path===ancestor.path){return false}if(ancestorPath===""){return true}if(ancestor.keys.length>=this.keys.length){return false}return ancestor.keys.every(((key,index)=>{const otherKey=this.keys[index];return otherKey===key||typeof otherKey==="string"&&(otherKey==="*"||otherKey[0]==="$")||typeof key==="string"&&(key==="*"||key[0]==="$")}))}isOnTrailOf(otherPath){const other=otherPath instanceof PathInfo?otherPath:new PathInfo(otherPath);if(this.path.length===0||other.path.length===0){return true}if(this.path===other.path){return true}return this.pathKeys.every(((key,index)=>{if(index>=other.keys.length){return true}const otherKey=other.keys[index];return otherKey===key||typeof otherKey==="string"&&(otherKey==="*"||otherKey[0]==="$")||typeof key==="string"&&(key==="*"||key[0]==="$")}))}isChildOf(otherPath){const other=otherPath instanceof PathInfo?otherPath:new PathInfo(otherPath);if(this.path===""){return false}return this.parent.equals(other)}isParentOf(otherPath){const other=otherPath instanceof PathInfo?otherPath:new PathInfo(otherPath);if(other.path===""){return false}return this.equals(other.parent)}}exports.PathInfo=PathInfo},{}],17:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PathReference=void 0;class PathReference{constructor(path){this.path=path}}exports.PathReference=PathReference},{}],18:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default={nextTick(fn){setTimeout(fn,0)}}},{}],19:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SchemaDefinition=void 0;function parse(definition){let pos=0;function consumeSpaces(){let c;while(c=definition[pos],[" ","\r","\n","\t"].includes(c)){pos++}}function consumeCharacter(c){if(definition[pos]!==c){throw new Error(`Unexpected character at position ${pos}. Expected: '${c}', found '${definition[pos]}'`)}pos++}function readProperty(){consumeSpaces();let prop={name:"",optional:false,wildcard:false},c;while(c=definition[pos],c==="_"||c==="$"||c>="a"&&c<="z"||c>="A"&&c<="Z"||prop.name.length>0&&c>="0"&&c<="9"||prop.name.length===0&&c==="*"){prop.name+=c;pos++}if(prop.name.length===0){throw new Error(`Property name expected at position ${pos}`)}if(definition[pos]==="?"){prop.optional=true;pos++}if(prop.name==="*"||prop.name[0]==="$"){prop.optional=true;prop.wildcard=true}consumeSpaces();consumeCharacter(":");return prop}function readType(){consumeSpaces();let type={typeOf:"any"},c;let name="";while(c=definition[pos],c>="a"&&c<="z"||c>="A"&&c<="Z"){name+=c;pos++}if(name.length===0){if(definition[pos]==="*"){consumeCharacter("*");type.typeOf="any"}else if([`'`,`"`,"`"].includes(definition[pos])){type.typeOf="string";type.value="";const quote=definition[pos];consumeCharacter(quote);while(c=definition[pos],c&&c!==quote){type.value+=c;pos++}consumeCharacter(quote)}else if(definition[pos]>="0"&&definition[pos]<="9"){type.typeOf="number";let nr="";while(c=definition[pos],c==="."||c>="0"&&c<="9"){nr+=c;pos++}type.value=nr.includes(".")?parseFloat(nr):parseInt(nr)}else if(definition[pos]==="{"){consumeCharacter("{");type.typeOf="object";type.instanceOf=Object;type.children=[];while(true){const prop=readProperty();const types=readTypes();type.children.push({name:prop.name,optional:prop.optional,wildcard:prop.wildcard,types:types});consumeSpaces();if(definition[pos]==="}"){break}consumeCharacter(",")}consumeCharacter("}")}else if(definition[pos]==="/"){consumeCharacter("/");let pattern="",flags="";while(c=definition[pos],c!=="/"||pattern.endsWith("\\")){pattern+=c;pos++}consumeCharacter("/");while(c=definition[pos],["g","i","m","s","u","y","d"].includes(c)){flags+=c;pos++}type.typeOf="string";type.matches=new RegExp(pattern,flags)}else{throw new Error(`Expected a type definition at position ${pos}, found character '${definition[pos]}'`)}}else if(["string","number","boolean","undefined","String","Number","Boolean"].includes(name)){type.typeOf=name.toLowerCase()}else if(name==="Object"||name==="object"){type.typeOf="object";type.instanceOf=Object}else if(name==="Date"){type.typeOf="object";type.instanceOf=Date}else if(name==="Binary"||name==="binary"){type.typeOf="object";type.instanceOf=ArrayBuffer}else if(name==="any"){type.typeOf="any"}else if(name==="null"){type.typeOf="object";type.value=null}else if(name==="Array"){consumeCharacter("<");type.typeOf="object";type.instanceOf=Array;type.genericTypes=readTypes();consumeCharacter(">")}else if(["true","false"].includes(name)){type.typeOf="boolean";type.value=name==="true"}else{throw new Error(`Unknown type at position ${pos}: "${type}"`)}consumeSpaces();while(definition[pos]==="["){consumeCharacter("[");consumeCharacter("]");type={typeOf:"object",instanceOf:Array,genericTypes:[type]}}return type}function readTypes(){consumeSpaces();const types=[readType()];while(definition[pos]==="|"){consumeCharacter("|");types.push(readType());consumeSpaces()}return types}return readType()}function checkObject(path,properties,obj,partial){const invalidProperties=properties.find((prop=>prop.name==="*"||prop.name[0]==="$"))?[]:Object.keys(obj).filter((key=>![null,undefined].includes(obj[key])&&!properties.find((prop=>prop.name===key))));if(invalidProperties.length>0){return{ok:false,reason:`Object at path "${path}" cannot have properties ${invalidProperties.map((p=>`"${p}"`)).join(", ")}`}}function checkProperty(property){const hasValue=![null,undefined].includes(obj[property.name]);if(!property.optional&&(partial?obj[property.name]===null:!hasValue)){return{ok:false,reason:`Property at path "${path}/${property.name}" is not optional`}}if(hasValue&&property.types.length===1){return checkType(`${path}/${property.name}`,property.types[0],obj[property.name],false)}if(hasValue&&!property.types.some((type=>checkType(`${path}/${property.name}`,type,obj[property.name],false).ok))){return{ok:false,reason:`Property at path "${path}/${property.name}" is of the wrong type`}}return{ok:true}}const namedProperties=properties.filter((prop=>!prop.wildcard));const failedProperty=namedProperties.find((prop=>!checkProperty(prop).ok));if(failedProperty){const reason=checkProperty(failedProperty).reason;return{ok:false,reason:reason}}const wildcardProperty=properties.find((prop=>prop.wildcard));if(!wildcardProperty){return{ok:true}}const wildcardChildKeys=Object.keys(obj).filter((key=>!namedProperties.find((prop=>prop.name===key))));let result={ok:true};for(let i=0;i<wildcardChildKeys.length&&result.ok;i++){const childKey=wildcardChildKeys[i];result=checkProperty({name:childKey,types:wildcardProperty.types,optional:true,wildcard:true})}return result}function checkType(path,type,value,partial,trailKeys){const ok={ok:true};if(type.typeOf==="any"){return ok}if(trailKeys instanceof Array&&trailKeys.length>0){if(type.typeOf!=="object"){return{ok:false,reason:`path "${path}" must be typeof ${type.typeOf}`}}if(!type.children){return ok}const childKey=trailKeys[0];let property=type.children.find((prop=>prop.name===childKey));if(!property){property=type.children.find((prop=>prop.name==="*"||prop.name[0]==="$"))}if(!property){return{ok:false,reason:`Object at path "${path}" cannot have property "${childKey}"`}}if(property.optional&&value===null&&trailKeys.length===1){return ok}let result;property.types.some((type=>{const childPath=typeof childKey==="number"?`${path}[${childKey}]`:`${path}/${childKey}`;result=checkType(childPath,type,value,partial,trailKeys.slice(1));return result.ok}));return result}if(value===null){return ok}if(typeof value!==type.typeOf){return{ok:false,reason:`path "${path}" must be typeof ${type.typeOf}`}}if(type.instanceOf===Object&&(typeof value!=="object"||value instanceof Array||value instanceof Date)){return{ok:false,reason:`path "${path}" must be an object collection`}}if(type.instanceOf&&(typeof value!=="object"||value.constructor!==type.instanceOf)){return{ok:false,reason:`path "${path}" must be an instance of ${type.instanceOf.name}`}}if("value"in type&&value!==type.value){return{ok:false,reason:`path "${path}" must be value: ${type.value}`}}if(type.instanceOf===Array&&type.genericTypes&&!value.every((v=>type.genericTypes.some((t=>checkType(path,t,v,false).ok))))){return{ok:false,reason:`every array value of path "${path}" must match one of the specified types`}}if(type.typeOf==="object"&&type.children){return checkObject(path,type.children,value,partial)}if(type.matches&&!type.matches.test(value)){return{ok:false,reason:`path "${path}" must match regular expression /${type.matches.source}/${type.matches.flags}`}}return ok}function getConstructorType(val){switch(val){case String:return"string";case Number:return"number";case Boolean:return"boolean";case Date:return"Date";case Array:throw new Error(`Schema error: Array cannot be used without a type. Use string[] or Array<string> instead`);default:throw new Error(`Schema error: unknown type used: ${val.name}`)}}class SchemaDefinition{constructor(definition){this.source=definition;if(typeof definition==="object"){const toTS=obj=>"{"+Object.keys(obj).map((key=>{let val=obj[key];if(val===undefined){val="undefined"}else if(val instanceof RegExp){val=`/${val.source}/${val.flags}`}else if(typeof val==="object"){val=toTS(val)}else if(typeof val==="function"){val=getConstructorType(val)}else if(!["string","number","boolean"].includes(typeof val)){throw new Error(`Type definition for key "${key}" must be a string, number, boolean, object, regular expression, or one of these classes: String, Number, Boolean, Date`)}return`${key}:${val}`})).join(",")+"}";this.text=toTS(definition)}else if(typeof definition==="string"){this.text=definition}else{throw new Error(`Type definiton must be a string or an object`)}this.type=parse(this.text)}check(path,value,partial,trailKeys){return checkType(path,this.type,value,partial,trailKeys)}}exports.SchemaDefinition=SchemaDefinition},{}],20:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SimpleCache=void 0;const utils_1=require("./utils");class SimpleCache{constructor(expirySeconds){this.enabled=true;this.expirySeconds=expirySeconds;this.cache=new Map;setInterval((()=>{this.cleanUp()}),60*1e3)}has(key){if(!this.enabled){return false}return this.cache.has(key)}get(key){if(!this.enabled){return null}const entry=this.cache.get(key);if(!entry){return null}return utils_1.cloneObject(entry.value)}set(key,value){this.cache.set(key,{value:utils_1.cloneObject(value),expires:Date.now()+this.expirySeconds*1e3})}remove(key){this.cache.delete(key)}cleanUp(){const now=Date.now();this.cache.forEach(((entry,key)=>{if(entry.expires<=now){this.cache.delete(key)}}))}}exports.SimpleCache=SimpleCache},{"./utils":26}],21:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Colorize=exports.SetColorsEnabled=exports.ColorsSupported=exports.ColorStyle=void 0;const process_1=require("./process");const FontCode={bold:1,dim:2,italic:3,underline:4,inverse:7,hidden:8,strikethrough:94};const ColorCode={black:30,red:31,green:32,yellow:33,blue:34,magenta:35,cyan:36,white:37,grey:90,brightRed:91};const BgColorCode={bgBlack:40,bgRed:41,bgGreen:42,bgYellow:43,bgBlue:44,bgMagenta:45,bgCyan:46,bgWhite:47,bgGrey:100,bgBrightRed:101};const ResetCode={all:0,color:39,background:49,bold:22,dim:22,italic:23,underline:24,inverse:27,hidden:28,strikethrough:29};var ColorStyle;(function(ColorStyle){ColorStyle["reset"]="reset";ColorStyle["bold"]="bold";ColorStyle["dim"]="dim";ColorStyle["italic"]="italic";ColorStyle["underline"]="underline";ColorStyle["inverse"]="inverse";ColorStyle["hidden"]="hidden";ColorStyle["strikethrough"]="strikethrough";ColorStyle["black"]="black";ColorStyle["red"]="red";ColorStyle["green"]="green";ColorStyle["yellow"]="yellow";ColorStyle["blue"]="blue";ColorStyle["magenta"]="magenta";ColorStyle["cyan"]="cyan";ColorStyle["grey"]="grey";ColorStyle["bgBlack"]="bgBlack";ColorStyle["bgRed"]="bgRed";ColorStyle["bgGreen"]="bgGreen";ColorStyle["bgYellow"]="bgYellow";ColorStyle["bgBlue"]="bgBlue";ColorStyle["bgMagenta"]="bgMagenta";ColorStyle["bgCyan"]="bgCyan";ColorStyle["bgWhite"]="bgWhite";ColorStyle["bgGrey"]="bgGrey"})(ColorStyle=exports.ColorStyle||(exports.ColorStyle={}));function ColorsSupported(){if(typeof process_1.default==="undefined"||!process_1.default.stdout||!process_1.default.env||!process_1.default.platform||process_1.default.platform==="browser"){return false}if(process_1.default.platform==="win32"){return true}const env=process_1.default.env;if(env.COLORTERM){return true}if(env.TERM==="dumb"){return false}if(env.CI||env.TEAMCITY_VERSION){return!!env.TRAVIS}if(["iTerm.app","HyperTerm","Hyper","MacTerm","Apple_Terminal","vscode"].includes(env.TERM_PROGRAM)){return true}if(/^xterm-256|^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(env.TERM)){return true}return false}exports.ColorsSupported=ColorsSupported;let _enabled=ColorsSupported();function SetColorsEnabled(enabled){_enabled=ColorsSupported()&&enabled}exports.SetColorsEnabled=SetColorsEnabled;function Colorize(str,style){if(!_enabled){return str}const openCodes=[],closeCodes=[];const addStyle=style=>{if(style===ColorStyle.reset){openCodes.push(ResetCode.all)}else if(style in FontCode){openCodes.push(FontCode[style]);closeCodes.push(ResetCode[style])}else if(style in ColorCode){openCodes.push(ColorCode[style]);closeCodes.push(ResetCode.color)}else if(style in BgColorCode){openCodes.push(BgColorCode[style]);closeCodes.push(ResetCode.background)}};if(style instanceof Array){style.forEach(addStyle)}else{addStyle(style)}const open=openCodes.map((code=>"["+code+"m")).join("");const close=closeCodes.map((code=>"["+code+"m")).join("");return str.split("\n").map((line=>open+line+close)).join("\n")}exports.Colorize=Colorize;String.prototype.colorize=function(style){return Colorize(this,style)}},{"./process":18}],22:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SimpleEventEmitter=void 0;function runCallback(callback,data){try{callback(data)}catch(err){console.error(`Error in subscription callback`,err)}}class SimpleEventEmitter{constructor(){this._subscriptions=[];this._oneTimeEvents=new Map}on(event,callback){if(this._oneTimeEvents.has(event)){return runCallback(callback,this._oneTimeEvents.get(event))}this._subscriptions.push({event:event,callback:callback,once:false});return this}off(event,callback){this._subscriptions=this._subscriptions.filter((s=>s.event!==event||callback&&s.callback!==callback));return this}once(event,callback){let resolve;let promise=new Promise((rs=>{if(!callback){resolve=rs}else{resolve=data=>{rs(data);callback(data)}}}));if(this._oneTimeEvents.has(event)){runCallback(resolve,this._oneTimeEvents.get(event))}else{this._subscriptions.push({event:event,callback:resolve,once:true})}return promise}emit(event,data){if(this._oneTimeEvents.has(event)){throw new Error(`Event "${event}" was supposed to be emitted only once`)}for(let i=0;i<this._subscriptions.length;i++){const s=this._subscriptions[i];if(s.event!==event){continue}try{s.callback(data)}catch(err){console.error(`Error in subscription callback`,err)}if(s.once){this._subscriptions.splice(i,1);i--}}return this}emitOnce(event,data){if(this._oneTimeEvents.has(event)){throw new Error(`Event "${event}" was supposed to be emitted only once`)}this.emit(event,data);this._oneTimeEvents.set(event,data);this.off(event);return this}}exports.SimpleEventEmitter=SimpleEventEmitter},{}],23:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.EventStream=exports.EventPublisher=exports.EventSubscription=void 0;class EventSubscription{constructor(stop){this.stop=stop;this._internal={state:"init",activatePromises:[]}}activated(callback){if(callback){this._internal.activatePromises.push({callback:callback});if(this._internal.state==="active"){callback(true)}else if(this._internal.state==="canceled"){callback(false,this._internal.cancelReason)}}return new Promise(((resolve,reject)=>{if(this._internal.state==="active"){return resolve()}else if(this._internal.state==="canceled"&&!callback){return reject(new Error(this._internal.cancelReason))}this._internal.activatePromises.push({resolve:resolve,reject:callback?()=>{}:reject})}))}_setActivationState(activated,cancelReason){this._internal.cancelReason=cancelReason;this._internal.state=activated?"active":"canceled";while(this._internal.activatePromises.length>0){const p=this._internal.activatePromises.shift();if(activated){p.callback&&p.callback(true);p.resolve&&p.resolve()}else{p.callback&&p.callback(false,cancelReason);p.reject&&p.reject(cancelReason)}}}}exports.EventSubscription=EventSubscription;class EventPublisher{constructor(publish,start,cancel){this.publish=publish;this.start=start;this.cancel=cancel}}exports.EventPublisher=EventPublisher;class EventStream{constructor(eventPublisherCallback){const subscribers=[];let noMoreSubscribersCallback;let activationState;const _stoppedState="stopped (no more subscribers)";this.subscribe=(callback,activationCallback)=>{if(typeof callback!=="function"){throw new TypeError("callback must be a function")}else if(activationState===_stoppedState){throw new Error("stream can't be used anymore because all subscribers were stopped")}const sub={callback:callback,activationCallback:function(activated,cancelReason){activationCallback&&activationCallback(activated,cancelReason);this.subscription._setActivationState(activated,cancelReason)},subscription:new EventSubscription((function stop(){subscribers.splice(subscribers.indexOf(this),1);return checkActiveSubscribers()}))};subscribers.push(sub);if(typeof activationState!=="undefined"){if(activationState===true){activationCallback&&activationCallback(true);sub.subscription._setActivationState(true)}else if(typeof activationState==="string"){activationCallback&&activationCallback(false,activationState);sub.subscription._setActivationState(false,activationState)}}return sub.subscription};const checkActiveSubscribers=()=>{let ret;if(subscribers.length===0){ret=noMoreSubscribersCallback&&noMoreSubscribersCallback();activationState=_stoppedState}return Promise.resolve(ret)};this.unsubscribe=callback=>{const remove=callback?subscribers.filter((sub=>sub.callback===callback)):subscribers;remove.forEach((sub=>{const i=subscribers.indexOf(sub);subscribers.splice(i,1)}));checkActiveSubscribers()};this.stop=()=>{subscribers.splice(0);checkActiveSubscribers()};const publish=val=>{subscribers.forEach((sub=>{try{sub.callback(val)}catch(err){console.error(`Error running subscriber callback: ${err.message}`)}}));if(subscribers.length===0){checkActiveSubscribers()}return subscribers.length>0};const start=allSubscriptionsStoppedCallback=>{activationState=true;noMoreSubscribersCallback=allSubscriptionsStoppedCallback;subscribers.forEach((sub=>{sub.activationCallback&&sub.activationCallback(true)}))};const cancel=reason=>{activationState=reason;subscribers.forEach((sub=>{sub.activationCallback&&sub.activationCallback(false,reason||new Error("unknown reason"))}));subscribers.splice(0)};const publisher=new EventPublisher(publish,start,cancel);eventPublisherCallback(publisher)}}exports.EventStream=EventStream},{}],24:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Transport=void 0;const path_reference_1=require("./path-reference");const utils_1=require("./utils");const ascii85_1=require("./ascii85");const path_info_1=require("./path-info");const partial_array_1=require("./partial-array");exports.Transport={deserialize(data){if(data.map===null||typeof data.map==="undefined"){return data.val}const deserializeValue=(type,val)=>{if(type==="date"){return new Date(val)}else if(type==="binary"){return ascii85_1.ascii85.decode(val)}else if(type==="reference"){return new path_reference_1.PathReference(val)}else if(type==="regexp"){return new RegExp(val.pattern,val.flags)}else if(type==="array"){return new partial_array_1.PartialArray(val)}return val};if(typeof data.map==="string"){return deserializeValue(data.map,data.val)}Object.keys(data.map).forEach((path=>{const type=data.map[path];const keys=path_info_1.PathInfo.getPathKeys(path);let parent=data;let key="val";let val=data.val;keys.forEach((k=>{key=k;parent=val;val=val[key]}));parent[key]=deserializeValue(type,val)}));return data.val},serialize(obj){if(obj===null||typeof obj!=="object"||obj instanceof Date||obj instanceof ArrayBuffer||obj instanceof path_reference_1.PathReference){const ser=this.serialize({value:obj});return{map:ser.map.value,val:ser.val.value}}obj=utils_1.cloneObject(obj);const process=(obj,mappings,prefix)=>{if(obj instanceof partial_array_1.PartialArray){mappings[prefix]="array"}Object.keys(obj).forEach((key=>{const val=obj[key];const path=prefix.length===0?key:`${prefix}/${key}`;if(val instanceof Date){obj[key]=val.toISOString();mappings[path]="date"}else if(val instanceof ArrayBuffer){obj[key]=ascii85_1.ascii85.encode(val);mappings[path]="binary"}else if(val instanceof path_reference_1.PathReference){obj[key]=val.path;mappings[path]="reference"}else if(val instanceof RegExp){obj[key]={pattern:val.source,flags:val.flags};mappings[path]="regexp"}else if(typeof val==="object"&&val!==null){process(val,mappings,path)}}))};const mappings={};process(obj,mappings,"");return{map:mappings,val:obj}}}},{"./ascii85":3,"./partial-array":15,"./path-info":16,"./path-reference":17,"./utils":26}],25:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.TypeMappings=void 0;const utils_1=require("./utils");const path_info_1=require("./path-info");const data_reference_1=require("./data-reference");const data_snapshot_1=require("./data-snapshot");function get(mappings,path){path=path.replace(/^\/|\/$/g,"");const keys=path_info_1.PathInfo.getPathKeys(path);const mappedPath=Object.keys(mappings).find((mpath=>{const mkeys=path_info_1.PathInfo.getPathKeys(mpath);if(mkeys.length!==keys.length){return false}return mkeys.every(((mkey,index)=>{if(mkey==="*"||mkey[0]==="$"){return true}return mkey===keys[index]}))}));const mapping=mappings[mappedPath];return mapping}function map(mappings,path){const targetPath=path_info_1.PathInfo.get(path).parentPath;if(targetPath===null){return}return get(mappings,targetPath)}function mapDeep(mappings,entryPath){entryPath=entryPath.replace(/^\/|\/$/g,"");const pathInfo=path_info_1.PathInfo.get(entryPath);const startPath=pathInfo.parentPath;const keys=startPath?path_info_1.PathInfo.getPathKeys(startPath):[];const matches=Object.keys(mappings).reduce(((m,mpath)=>{const mkeys=path_info_1.PathInfo.getPathKeys(mpath);if(mkeys.length<keys.length){return m}let isMatch=true;if(keys.length===0&&startPath!==null){isMatch=mkeys.length===1&&(mkeys[0]==="*"||mkeys[0][0]==="$")}else{mkeys.every(((mkey,index)=>{if(index>=keys.length){return false}else if(mkey==="*"||mkey[0]==="$"||mkey===keys[index]){return true}else{isMatch=false;return false}}))}if(isMatch){const mapping=mappings[mpath];m.push({path:mpath,type:mapping})}return m}),[]);return matches}function process(db,mappings,path,obj,action){if(obj===null||typeof obj!=="object"){return obj}const keys=path_info_1.PathInfo.getPathKeys(path);const m=mapDeep(mappings,path);const changes=[];m.sort(((a,b)=>path_info_1.PathInfo.getPathKeys(a.path).length>path_info_1.PathInfo.getPathKeys(b.path).length?-1:1));m.forEach((mapping=>{const mkeys=path_info_1.PathInfo.getPathKeys(mapping.path);mkeys.push("*");const mTrailKeys=mkeys.slice(keys.length);if(mTrailKeys.length===0){const vars=path_info_1.PathInfo.extractVariables(mapping.path,path);const ref=new data_reference_1.DataReference(db,path,vars);if(action==="serialize"){obj=mapping.type.serialize(obj,ref)}else if(action==="deserialize"){const snap=new data_snapshot_1.DataSnapshot(ref,obj);obj=mapping.type.deserialize(snap)}return}const process=(parentPath,parent,keys)=>{if(obj===null||typeof obj!=="object"){return obj}const key=keys[0];let children=[];if(key==="*"||key[0]==="$"){if(parent instanceof Array){children=parent.map(((val,index)=>({key:index,val:val})))}else{children=Object.keys(parent).map((k=>({key:k,val:parent[k]})))}}else{const child=parent[key];if(typeof child==="object"){children.push({key:key,val:child})}}children.forEach((child=>{const childPath=path_info_1.PathInfo.getChildPath(parentPath,child.key);const vars=path_info_1.PathInfo.extractVariables(mapping.path,childPath);const ref=new data_reference_1.DataReference(db,childPath,vars);if(keys.length===1){if(action==="serialize"){changes.push({parent:parent,key:child.key,original:parent[child.key]});parent[child.key]=mapping.type.serialize(child.val,ref)}else if(action==="deserialize"){const snap=new data_snapshot_1.DataSnapshot(ref,child.val);parent[child.key]=mapping.type.deserialize(snap)}}else{process(childPath,child.val,keys.slice(1))}}))};process(path,obj,mTrailKeys)}));if(action==="serialize"){obj=utils_1.cloneObject(obj);if(changes.length>0){changes.forEach((change=>{change.parent[change.key]=change.original}))}}return obj}const _mappings=Symbol("mappings");class TypeMappings{constructor(db){this.db=db;this[_mappings]={}}get mappings(){return this[_mappings]}map(path){return map(this[_mappings],path)}bind(path,type,options={}){if(typeof path!=="string"){throw new TypeError("path must be a string")}if(typeof type!=="function"){throw new TypeError("constructor must be a function")}if(typeof options.serializer==="undefined"){}else if(typeof options.serializer==="string"){if(typeof type.prototype[options.serializer]==="function"){options.serializer=type.prototype[options.serializer]}else{throw new TypeError(`${type.name}.prototype.${options.serializer} is not a function, cannot use it as serializer`)}}else if(typeof options.serializer!=="function"){throw new TypeError(`serializer for class ${type.name} must be a function, or the name of a prototype method`)}if(typeof options.creator==="undefined"){if(typeof type.create==="function"){options.creator=type.create}}else if(typeof options.creator==="string"){if(typeof type[options.creator]==="function"){options.creator=type[options.creator]}else{throw new TypeError(`${type.name}.${options.creator} is not a function, cannot use it as creator`)}}else if(typeof options.creator!=="function"){throw new TypeError(`creator for class ${type.name} must be a function, or the name of a static method`)}path=path.replace(/^\/|\/$/g,"");this[_mappings][path]={db:this.db,type:type,creator:options.creator,serializer:options.serializer,deserialize(snap){let obj;if(this.creator){obj=this.creator.call(this.type,snap)}else{obj=new this.type(snap)}return obj},serialize(obj,ref){if(this.serializer){obj=this.serializer.call(obj,ref,obj)}else if(obj&&typeof obj.serialize==="function"){obj=obj.serialize(ref,obj)}return obj}}}serialize(path,obj){return process(this.db,this[_mappings],path,obj,"serialize")}deserialize(path,obj){return process(this.db,this[_mappings],path,obj,"deserialize")}}exports.TypeMappings=TypeMappings},{"./data-reference":8,"./data-snapshot":9,"./path-info":16,"./utils":26}],26:[function(require,module,exports){(function(Buffer){(function(){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.defer=exports.getChildValues=exports.getMutations=exports.compareValues=exports.ObjectDifferences=exports.valuesAreEqual=exports.cloneObject=exports.concatTypedArrays=exports.decodeString=exports.encodeString=exports.bytesToNumber=exports.numberToBytes=void 0;const path_reference_1=require("./path-reference");const process_1=require("./process");const partial_array_1=require("./partial-array");function numberToBytes(number){const bytes=new Uint8Array(8);const view=new DataView(bytes.buffer);view.setFloat64(0,number);return new Array(...bytes)}exports.numberToBytes=numberToBytes;function bytesToNumber(bytes){if(bytes.length<8){throw new TypeError("must be 8 bytes")}const bin=new Uint8Array(bytes);const view=new DataView(bin.buffer);const nr=view.getFloat64(0);return nr}exports.bytesToNumber=bytesToNumber;function encodeString(str){if(typeof TextEncoder!=="undefined"){const encoder=new TextEncoder;return encoder.encode(str)}else if(typeof Buffer==="function"){const buf=Buffer.from(str,"utf-8");return new Uint8Array(buf.buffer,buf.byteOffset,buf.byteLength)}else{let arr=[];for(let i=0;i<str.length;i++){let code=str.charCodeAt(i);if(code>128){if((code&55296)===55296){const nextCode=str.charCodeAt(i+1);if((nextCode&56320)!==56320){throw new Error("follow-up utf-16 character does not start with 0xDC00")}i++;const p1=code&1023;const p2=nextCode&1023;code=65536|p1<<10|p2}if(code<2048){const b1=192|code>>6&31;const b2=128|code&63;arr.push(b1,b2)}else if(code<65536){const b1=224|code>>12&15;const b2=128|code>>6&63;const b3=128|code&63;arr.push(b1,b2,b3)}else if(code<2097152){const b1=240|code>>18&7;const b2=128|code>>12&63;const b3=128|code>>6&63;const b4=128|code&63;arr.push(b1,b2,b3,b4)}else{throw new Error(`Cannot convert character ${str.charAt(i)} (code ${code}) to utf-8`)}}else{arr.push(code<128?code:63)}}return new Uint8Array(arr)}}exports.encodeString=encodeString;function decodeString(buffer){if(typeof TextDecoder!=="undefined"){const decoder=new TextDecoder;if(buffer instanceof Uint8Array){return decoder.decode(buffer)}const buf=Uint8Array.from(buffer);return decoder.decode(buf)}else if(typeof Buffer==="function"){if(buffer instanceof Buffer){return buffer.toString("utf-8")}else if(buffer instanceof Array){const typedArray=Uint8Array.from(buffer);const buf=Buffer.from(typedArray.buffer,typedArray.byteOffset,typedArray.byteOffset+typedArray.byteLength);return buf.toString("utf-8")}else if("buffer"in buffer&&buffer["buffer"]instanceof ArrayBuffer){const buf=Buffer.from(buffer["buffer"],buffer.byteOffset,buffer.byteOffset+buffer.byteLength);return buf.toString("utf-8")}else{throw new Error(`Unsupported buffer argument`)}}else{if(!(buffer instanceof Uint8Array)&&"buffer"in buffer&&buffer["buffer"]instanceof ArrayBuffer){buffer=new Uint8Array(buffer["buffer"],buffer.byteOffset,buffer.byteLength)}if(buffer instanceof Buffer||buffer instanceof Array||buffer instanceof Uint8Array){let str="";for(let i=0;i<buffer.length;i++){let code=buffer[i];if(code>128){if((code&240)===240){const b1=code,b2=buffer[i+1],b3=buffer[i+2],b4=buffer[i+3];code=(b1&7)<<18|(b2&63)<<12|(b3&63)<<6|b4&63;i+=3}else if((code&224)===224){const b1=code,b2=buffer[i+1],b3=buffer[i+2];code=(b1&15)<<12|(b2&63)<<6|b3&63;i+=2}else if((code&192)===192){const b1=code,b2=buffer[i+1];code=(b1&31)<<6|b2&63;i++}else{throw new Error(`invalid utf-8 data`)}}if(code>=65536){code^=65536;const p1=55296|code>>10;const p2=56320|code&1023;str+=String.fromCharCode(p1);str+=String.fromCharCode(p2)}else{str+=String.fromCharCode(code)}}return str}else{throw new Error(`Unsupported buffer argument`)}}}exports.decodeString=decodeString;function concatTypedArrays(a,b){const c=new a.constructor(a.length+b.length);c.set(a);c.set(b,a.length);return c}exports.concatTypedArrays=concatTypedArrays;function cloneObject(original,stack){const{DataSnapshot:DataSnapshot}=require("./data-snapshot");if(original instanceof DataSnapshot){throw new TypeError(`Object to clone is a DataSnapshot (path "${original.ref.path}")`)}const checkAndFixTypedArray=obj=>{if(obj!==null&&typeof obj==="object"&&typeof obj.constructor==="function"&&typeof obj.constructor.name==="string"&&["Buffer","Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","BigUint64Array","BigInt64Array"].includes(obj.constructor.name)){obj=obj.buffer.slice(obj.byteOffset,obj.byteOffset+obj.byteLength)}return obj};original=checkAndFixTypedArray(original);if(typeof original!=="object"||original===null||original instanceof Date||original instanceof ArrayBuffer||original instanceof path_reference_1.PathReference||original instanceof RegExp){return original}const cloneValue=val=>{if(stack.indexOf(val)>=0){throw new ReferenceError(`object contains a circular reference`)}val=checkAndFixTypedArray(val);if(val===null||val instanceof Date||val instanceof ArrayBuffer||val instanceof path_reference_1.PathReference||val instanceof RegExp){return val}else if(typeof val==="object"){stack.push(val);val=cloneObject(val,stack);stack.pop();return val}else{return val}};if(typeof stack==="undefined"){stack=[original]}const clone=original instanceof Array?[]:original instanceof partial_array_1.PartialArray?new partial_array_1.PartialArray:{};Object.keys(original).forEach((key=>{let val=original[key];if(typeof val==="function"){return}clone[key]=cloneValue(val)}));return clone}exports.cloneObject=cloneObject;const isTypedArray=val=>typeof val==="object"&&["ArrayBuffer","Buffer","Uint8Array","Uint16Array","Uint32Array","Int8Array","Int16Array","Int32Array"].includes(val.constructor.name);function valuesAreEqual(val1,val2){if(val1===val2){return true}if(typeof val1!==typeof val2){return false}if(typeof val1==="object"||typeof val2==="object"){if(val1===null||val2===null){return false}if(val1 instanceof path_reference_1.PathReference||val2 instanceof path_reference_1.PathReference){return val1 instanceof path_reference_1.PathReference&&val2 instanceof path_reference_1.PathReference&&val1.path===val2.path}if(val1 instanceof Date||val2 instanceof Date){return val1 instanceof Date&&val2 instanceof Date&&val1.getTime()===val2.getTime()}if(val1 instanceof Array||val2 instanceof Array){return val1 instanceof Array&&val2 instanceof Array&&val1.length===val2.length&&val1.every(((item,i)=>valuesAreEqual(val1[i],val2[i])))}if(isTypedArray(val1)||isTypedArray(val2)){if(!isTypedArray(val1)||!isTypedArray(val2)||val1.byteLength===val2.byteLength){return false}const typed1=val1 instanceof ArrayBuffer?new Uint8Array(val1):new Uint8Array(val1.buffer,val1.byteOffset,val1.byteLength),typed2=val2 instanceof ArrayBuffer?new Uint8Array(val2):new Uint8Array(val2.buffer,val2.byteOffset,val2.byteLength);return typed1.every(((val,i)=>typed2[i]===val))}const keys1=Object.keys(val1),keys2=Object.keys(val2);return keys1.length===keys2.length&&keys1.every((key=>keys2.includes(key)))&&keys1.every((key=>valuesAreEqual(val1[key],val2[key])))}return false}exports.valuesAreEqual=valuesAreEqual;class ObjectDifferences{constructor(added,removed,changed){this.added=added;this.removed=removed;this.changed=changed}forChild(key){if(this.added.includes(key)){return"added"}if(this.removed.includes(key)){return"removed"}const changed=this.changed.find((ch=>ch.key===key));return changed?changed.change:"identical"}}exports.ObjectDifferences=ObjectDifferences;function compareValues(oldVal,newVal,sortedResults=false){const voids=[undefined,null];if(oldVal===newVal){return"identical"}else if(voids.indexOf(oldVal)>=0&&voids.indexOf(newVal)<0){return"added"}else if(voids.indexOf(oldVal)<0&&voids.indexOf(newVal)>=0){return"removed"}else if(typeof oldVal!==typeof newVal){return"changed"}else if(isTypedArray(oldVal)||isTypedArray(newVal)){if(!isTypedArray(oldVal)||!isTypedArray(newVal)){return"changed"}const typed1=oldVal instanceof Uint8Array?oldVal:oldVal instanceof ArrayBuffer?new Uint8Array(oldVal):new Uint8Array(oldVal.buffer,oldVal.byteOffset,oldVal.byteLength);const typed2=newVal instanceof Uint8Array?newVal:newVal instanceof ArrayBuffer?new Uint8Array(newVal):new Uint8Array(newVal.buffer,newVal.byteOffset,newVal.byteLength);return typed1.byteLength===typed2.byteLength&&typed1.every(((val,i)=>typed2[i]===val))?"identical":"changed"}else if(oldVal instanceof Date||newVal instanceof Date){return oldVal instanceof Date&&newVal instanceof Date&&oldVal.getTime()===newVal.getTime()?"identical":"changed"}else if(oldVal instanceof path_reference_1.PathReference||newVal instanceof path_reference_1.PathReference){return oldVal instanceof path_reference_1.PathReference&&newVal instanceof path_reference_1.PathReference&&oldVal.path===newVal.path?"identical":"changed"}else if(typeof oldVal==="object"){const isArray=oldVal instanceof Array;const getKeys=obj=>{let keys=Object.keys(obj).filter((key=>!voids.includes(obj[key])));if(isArray){keys=keys.map((v=>parseInt(v)))}return keys};const oldKeys=getKeys(oldVal);const newKeys=getKeys(newVal);const removedKeys=oldKeys.filter((key=>!newKeys.includes(key)));const addedKeys=newKeys.filter((key=>!oldKeys.includes(key)));const changedKeys=newKeys.reduce(((changed,key)=>{if(oldKeys.includes(key)){const val1=oldVal[key];const val2=newVal[key];const c=compareValues(val1,val2);if(c!=="identical"){changed.push({key:key,change:c})}}return changed}),[]);if(addedKeys.length===0&&removedKeys.length===0&&changedKeys.length===0){return"identical"}else{return new ObjectDifferences(addedKeys,removedKeys,sortedResults?changedKeys.sort(((a,b)=>a.key<b.key?-1:1)):changedKeys)}}return"changed"}exports.compareValues=compareValues;function getMutations(oldVal,newVal,sortedResults=false){const process=(target,compareResult,prev,val)=>{switch(compareResult){case"identical":return[];case"changed":return[{target:target,prev:prev,val:val}];case"added":return[{target:target,prev:null,val:val}];case"removed":return[{target:target,prev:prev,val:null}];default:{let changes=[];compareResult.added.forEach((key=>changes.push({target:target.concat(key),prev:null,val:val[key]})));compareResult.removed.forEach((key=>changes.push({target:target.concat(key),prev:prev[key],val:null})));compareResult.changed.forEach((item=>{const childChanges=process(target.concat(item.key),item.change,prev[item.key],val[item.key]);changes=changes.concat(childChanges)}));return changes}}};const compareResult=compareValues(oldVal,newVal,sortedResults);return process([],compareResult,oldVal,newVal)}exports.getMutations=getMutations;function getChildValues(childKey,oldValue,newValue){oldValue=oldValue===null?null:oldValue[childKey];if(typeof oldValue==="undefined"){oldValue=null}newValue=newValue===null?null:newValue[childKey];if(typeof newValue==="undefined"){newValue=null}return{oldValue:oldValue,newValue:newValue}}exports.getChildValues=getChildValues;function defer(fn){process_1.default.nextTick(fn)}exports.defer=defer}).call(this)}).call(this,require("buffer").Buffer)},{"./data-snapshot":9,"./partial-array":15,"./path-reference":17,"./process":18,buffer:41}],27:[function(require,module,exports){const{SimpleCache:SimpleCache}=require("acebase-core");const{AceBase:AceBase,AceBaseLocalSettings:AceBaseLocalSettings}=require("./acebase-local");const{CustomStorageSettings:CustomStorageSettings,CustomStorageTransaction:CustomStorageTransaction,CustomStorageHelpers:CustomStorageHelpers,ICustomStorageNode:ICustomStorageNode,ICustomStorageNodeMetaData:ICustomStorageNodeMetaData}=require("./storage-custom");const deprecatedConstructorError=`Using AceBase constructor in the browser to use localStorage is deprecated!\nSwitch to:\nIndexedDB implementation (FASTER, MORE RELIABLE):\n let db = AceBase.WithIndexedDB(name, settings)\nOr, new LocalStorage implementation:\n let db = AceBase.WithLocalStorage(name, settings)\nOr, write your own CustomStorage adapter:\n let myCustomStorage = new CustomStorageSettings({ ... });\n let db = new AceBase(name, { storage: myCustomStorage })`;class BrowserAceBase extends AceBase{constructor(name,settings){if(typeof settings!=="object"||typeof settings.storage!=="object"){throw new Error(deprecatedConstructorError)}super(name,settings);this.settings.ipcEvents=settings.multipleTabs===true}static WithIndexedDB(dbname,settings){settings=settings||{};if(!settings.logLevel){settings.logLevel="error"}const IndexedDB=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;let request=IndexedDB.open(`${dbname}.acebase`,1);let readyResolve,readyReject,readyPromise=new Promise(((rs,rj)=>{readyResolve=rs;readyReject=rj}));request.onupgradeneeded=e=>{let db=request.result;db.createObjectStore("nodes",{keyPath:"path"});db.createObjectStore("content")};let db;request.onsuccess=e=>{db=request.result;readyResolve()};request.onerror=e=>{readyReject(e)};const cache=new SimpleCache(typeof settings.cacheSeconds==="number"?settings.cacheSeconds:60);const storageSettings=new CustomStorageSettings({name:"IndexedDB",locking:true,removeVoidProperties:settings.removeVoidProperties,maxInlineValueSize:settings.maxInlineValueSize,lockTimeout:settings.lockTimeout,ready(){return readyPromise},async getTransaction(target){await readyPromise;const context={debug:false,db:db,cache:cache,ipc:ipc};return new IndexedDBStorageTransaction(context,target)}});const acebase=new BrowserAceBase(dbname,{multipleTabs:settings.multipleTabs,logLevel:settings.logLevel,storage:storageSettings});const ipc=acebase.api.storage.ipc;ipc.on("notification",(async notification=>{const message=notification.data;if(typeof message!=="object"){return}if(message.action==="cache.invalidate"){for(let path of message.paths){cache.remove(path)}}}));return acebase}}function _requestToPromise(request){return new Promise(((resolve,reject)=>{request.onsuccess=event=>resolve(request.result||null);request.onerror=reject}))}class IndexedDBStorageTransaction extends CustomStorageTransaction{constructor(context,target){super(target);this.production=true;this.context=context;this._pending=[]}_createTransaction(write=false){const tx=this.context.db.transaction(["nodes","content"],write?"readwrite":"readonly");return tx}_splitMetadata(node){const copy={};const value=node.value;Object.assign(copy,node);delete copy.value;const metadata=copy;return{metadata:metadata,value:value}}async commit(){if(this._pending.length===0){return}const batch=this._pending.splice(0);this.context.ipc.sendMessage({type:"notification",data:{action:"cache.invalidate",paths:batch.map((op=>op.path))}});const tx=this._createTransaction(true);try{await new Promise(((resolve,reject)=>{let stop=false,processed=0;const handleError=err=>{stop=true;reject(err)};const handleSuccess=()=>{if(++processed===batch.length){resolve()}};batch.forEach(((op,i)=>{if(stop){return}let r1,r2;const path=op.path;if(op.action==="set"){const{metadata:metadata,value:value}=this._splitMetadata(op.node);const nodeInfo={path:path,metadata:metadata};r1=tx.objectStore("nodes").put(nodeInfo);r2=tx.objectStore("content").put(value,path);this.context.cache.set(path,op.node)}else if(op.action==="remove"){r1=tx.objectStore("content").delete(path);r2=tx.objectStore("nodes").delete(path);this.context.cache.set(path,null)}else{handleError(new Error(`Unknown pending operation "${op.action}" on path "${path}" `))}let succeeded=0;r1.onsuccess=r2.onsuccess=()=>{if(++succeeded===2){handleSuccess()}};r1.onerror=r2.onerror=handleError}))}));tx.commit&&tx.commit()}catch(err){console.error(err);tx.abort&&tx.abort();throw err}}async rollback(err){this._pending=[]}async get(path){if(this.context.cache.has(path)){const cache=this.context.cache.get(path);return cache}const tx=this._createTransaction(false);const r1=_requestToPromise(tx.objectStore("nodes").get(path));const r2=_requestToPromise(tx.objectStore("content").get(path));try{const results=await Promise.all([r1,r2]);tx.commit&&tx.commit();const info=results[0];if(!info){this.context.cache.set(path,null);return null}const node=info.metadata;node.value=results[1];this.context.cache.set(path,node);return node}catch(err){console.error(`IndexedDB get error`,err);tx.abort&&tx.abort();throw err}}set(path,node){this._pending.push({action:"set",path:path,node:node})}remove(path){this._pending.push({action:"remove",path:path})}removeMultiple(paths){paths.forEach((path=>{this._pending.push({action:"remove",path:path})}))}childrenOf(path,include,checkCallback,addCallback){include.descendants=false;return this._getChildrenOf(path,include,checkCallback,addCallback)}descendantsOf(path,include,checkCallback,addCallback){include.descendants=true;return this._getChildrenOf(path,include,checkCallback,addCallback)}_getChildrenOf(path,include,checkCallback,addCallback){return new Promise(((resolve,reject)=>{const pathInfo=CustomStorageHelpers.PathInfo.get(path);const tx=this._createTransaction(false);const store=tx.objectStore("nodes");const query=IDBKeyRange.lowerBound(path,true);const cursor=include.metadata?store.openCursor(query):store.openKeyCursor(query);cursor.onerror=e=>{tx.abort&&tx.abort();reject(e)};cursor.onsuccess=async e=>{const otherPath=cursor.result?cursor.result.key:null;let keepGoing=true;if(otherPath===null){keepGoing=false}else if(!pathInfo.isAncestorOf(otherPath)){keepGoing=false}else if(include.descendants||pathInfo.isParentOf(otherPath)){let node;if(include.metadata){const valueCursor=cursor;const data=valueCursor.result.value;node=data.metadata}const shouldAdd=checkCallback(otherPath,node);if(shouldAdd){if(include.value){if(this.context.cache.has(otherPath)){const cache=this.context.cache.get(otherPath);node.value=cache.value}else{const req=tx.objectStore("content").get(otherPath);node.value=await new Promise(((resolve,reject)=>{req.onerror=e=>{resolve(null)};req.onsuccess=e=>{resolve(req.result)}}));this.context.cache.set(otherPath,node.value===null?null:node)}}keepGoing=addCallback(otherPath,node)}}if(keepGoing){try{cursor.result.continue()}catch(err){keepGoing=false}}if(!keepGoing){tx.commit&&tx.commit();resolve()}}}))}}module.exports={BrowserAceBase:BrowserAceBase}},{"./acebase-local":28,"./storage-custom":39,"acebase-core":12}],28:[function(require,module,exports){const{AceBaseBase:AceBaseBase,AceBaseBaseSettings:AceBaseBaseSettings}=require("acebase-core");const{LocalApi:LocalApi}=require("./api-local");const{CustomStorageSettings:CustomStorageSettings,CustomStorageTransaction:CustomStorageTransaction,CustomStorageHelpers:CustomStorageHelpers}=require("./storage-custom");class AceBaseLocalSettings extends AceBaseBaseSettings{constructor(options){super(options);if(!options){options={}}this.storage=options.storage||{};if(typeof options.ipc==="object"){options.storage.ipc=options.ipc}if(typeof options.transactions==="object"){options.storage.transactions=options.transactions}}}class AceBase extends AceBaseBase{constructor(dbname,options){options=new AceBaseLocalSettings(options);options.info=options.info||"realtime database";super(dbname,options);const apiSettings={db:this,storage:options.storage,logLevel:options.logLevel};this.api=new LocalApi(dbname,apiSettings,(()=>{this.emit("ready")}))}close(){return this.api.storage.close()}get settings(){const ipc=this.api.storage.ipc,debug=this.debug;return{get logLevel(){return debug.level},set logLevel(level){debug.setLevel(level)},get ipcEvents(){return ipc.eventsEnabled},set ipcEvents(enabled){ipc.eventsEnabled=enabled}}}static WithLocalStorage(dbname,settings){settings=settings||{};if(!settings.logLevel){settings.logLevel="error"}const localStorage=settings.provider?settings.provider:settings.temp?window.localStorage:window.sessionStorage;const storageSettings=new CustomStorageSettings({name:"LocalStorage",locking:true,removeVoidProperties:settings.removeVoidProperties,maxInlineValueSize:settings.maxInlineValueSize,ready(){return Promise.resolve()},getTransaction(target){const context={debug:true,dbname:dbname,localStorage:localStorage};const transaction=new LocalStorageTransaction(context,target);return Promise.resolve(transaction)}});const db=new AceBase(dbname,{logLevel:settings.logLevel,storage:storageSettings});db.settings.ipcEvents=settings.multipleTabs===true;return db}}class LocalStorageTransaction extends CustomStorageTransaction{constructor(context,target){super(target);this.context=context;this._storageKeysPrefix=`${this.context.dbname}.acebase::`}async commit(){}async rollback(err){}async get(path){const json=this.context.localStorage.getItem(this.getStorageKeyForPath(path));const val=JSON.parse(json);return val}async set(path,val){const json=JSON.stringify(val);this.context.localStorage.setItem(this.getStorageKeyForPath(path),json)}async remove(path){this.context.localStorage.removeItem(this.getStorageKeyForPath(path))}async childrenOf(path,include,checkCallback,addCallback){const pathInfo=CustomStorageHelpers.PathInfo.get(path);for(let i=0;i<this.context.localStorage.length;i++){const key=this.context.localStorage.key(i);if(!key.startsWith(this._storageKeysPrefix)){continue}let otherPath=this.getPathFromStorageKey(key);if(pathInfo.isParentOf(otherPath)&&checkCallback(otherPath)){let node;if(include.metadata||include.value){const json=this.context.localStorage.getItem(key);node=JSON.parse(json)}const keepGoing=addCallback(otherPath,node);if(!keepGoing){break}}}}async descendantsOf(path,include,checkCallback,addCallback){const pathInfo=CustomStorageHelpers.PathInfo.get(path);for(let i=0;i<this.context.localStorage.length;i++){const key=this.context.localStorage.key(i);if(!key.startsWith(this._storageKeysPrefix)){continue}let otherPath=this.getPathFromStorageKey(key);if(pathInfo.isAncestorOf(otherPath)&&checkCallback(otherPath)){let node;if(include.metadata||include.value){const json=this.context.localStorage.getItem(key);node=JSON.parse(json)}const keepGoing=addCallback(otherPath,node);if(!keepGoing){break}}}}getPathFromStorageKey(key){return key.slice(this._storageKeysPrefix.length)}getStorageKeyForPath(path){return`${this._storageKeysPrefix}${path}`}}module.exports={AceBase:AceBase,AceBaseLocalSettings:AceBaseLocalSettings}},{"./api-local":29,"./storage-custom":39,"acebase-core":12}],29:[function(require,module,exports){const{Api:Api,ID:ID}=require("acebase-core");const{StorageSettings:StorageSettings,NodeNotFoundError:NodeNotFoundError}=require("./storage");const{AceBaseStorage:AceBaseStorage,AceBaseStorageSettings:AceBaseStorageSettings}=require("./storage-acebase");const{SQLiteStorage:SQLiteStorage,SQLiteStorageSettings:SQLiteStorageSettings}=require("./storage-sqlite");const{MSSQLStorage:MSSQLStorage,MSSQLStorageSettings:MSSQLStorageSettings}=require("./storage-mssql");const{CustomStorage:CustomStorage,CustomStorageSettings:CustomStorageSettings}=require("./storage-custom");const{Node:Node}=require("./node");const{DataIndex:DataIndex}=require("./data-index");class LocalApi extends Api{constructor(dbname="default",settings,readyCallback){super();this.db=settings.db;if(typeof settings.storage==="object"){settings.storage.logLevel=settings.logLevel;if(SQLiteStorageSettings&&(settings.storage instanceof SQLiteStorageSettings||settings.storage.type==="sqlite")){this.storage=new SQLiteStorage(dbname,settings.storage)}else if(MSSQLStorageSettings&&(settings.storage instanceof MSSQLStorageSettings||settings.storage.type==="mssql")){this.storage=new MSSQLStorage(dbname,settings.storage)}else if(CustomStorageSettings&&(settings.storage instanceof CustomStorageSettings||settings.storage.type==="custom")){this.storage=new CustomStorage(dbname,settings.storage)}else{const storageSettings=settings.storage instanceof AceBaseStorageSettings?settings.storage:new AceBaseStorageSettings(settings.storage);this.storage=new AceBaseStorage(dbname,storageSettings)}}else{settings.storage=new AceBaseStorageSettings({logLevel:settings.logLevel});this.storage=new AceBaseStorage(dbname,settings.storage)}this.storage.on("ready",readyCallback)}stats(options){return Promise.resolve(this.storage.stats)}subscribe(path,event,callback){this.storage.subscriptions.add(path,event,callback)}unsubscribe(path,event=undefined,callback=undefined){this.storage.subscriptions.remove(path,event,callback)}set(path,value,options={suppress_events:false,context:null}){return Node.update(this.storage,path,value,{merge:false,suppress_events:options.suppress_events,context:options.context})}update(path,updates,options={suppress_events:false,context:null}){return Node.update(this.storage,path,updates,{merge:true,suppress_events:options.suppress_events,context:options.context})}get transactionLoggingEnabled(){return this.storage.settings.transactions&&this.storage.settings.transactions.log===true}async get(path,options){const context={};if(this.transactionLoggingEnabled){context.acebase_cursor=ID.generate()}const value=await Node.getValue(this.storage,path,options);return{value:value,context:context}}transaction(path,callback,options={suppress_events:false,context:null}){return Node.transaction(this.storage,path,callback,{suppress_events:options.suppress_events,context:options.context})}exists(path){return Node.exists(this.storage,path)}query2(path,query,options={snapshots:false,include:undefined,exclude:undefined,child_objects:undefined}){}query(path,query,options={snapshots:false,include:undefined,exclude:undefined,child_objects:undefined,eventHandler:event=>{}}){if(typeof options!=="object"){options={}}if(typeof options.snapshots==="undefined"){options.snapshots=false}const context={};if(this.transactionLoggingEnabled){context.acebase_cursor=ID.generate()}const sortMatches=matches=>{matches.sort(((a,b)=>{const compare=i=>{const o=query.order[i];let left=a.val[o.key];let right=b.val[o.key];if(typeof left==="undefined"&&typeof right!=="undefined"){return o.ascending?-1:1}if(typeof left!=="undefined"&&typeof right==="undefined"){return o.ascending?1:-1}if(typeof left==="undefined"&&typeof right==="undefined"){return 0}if(left==right){if(i<query.order.length-1){return compare(i+1)}else{return a.path<b.path?-1:1}}else if(left<right){return o.ascending?-1:1}else if(left>right){return o.ascending?1:-1}};return compare(0)}))};const loadResultsData=(preResults,options)=>{if(preResults.length===0){return Promise.resolve([])}const maxBatchSize=50;let batches=[];const items=preResults.map(((result,index)=>({path:result.path,index:index})));while(items.length>0){let batchItems=items.splice(0,maxBatchSize);batches.push(batchItems)}const results=[];const nextBatch=()=>{const batch=batches.shift();return Promise.all(batch.map((item=>{const{path:path,index:index}=item;return Node.getValue(this.storage,path,options).then((val=>{if(val===null){this.storage.debug.warn(`Indexed result "/${path}" does not have a record!`);return}const result={path:path,val:val};if(stepsExecuted.sorted){results[index]=result}else{results.push(result);if(!stepsExecuted.skipped&&results.length>query.skip+Math.abs(query.take)){sortMatches(results);if(query.take<0){results.shift()}else{results.pop()}}}}))}))).then((()=>{if(batches.length>0){return nextBatch()}}))};return nextBatch().then((()=>results))};const isWildcardPath=path.includes("*");const availableIndexes=this.storage.indexes.get(path);const usingIndexes=[];query.filters.forEach((filter=>{if(filter.index){return}const indexesOnKey=availableIndexes.filter((index=>index.key===filter.key)).filter((index=>index.validOperators.includes(filter.op)));if(indexesOnKey.length>=1){const otherFilterKeys=query.filters.filter((f=>f!==filter)).map((f=>f.key));const sortKeys=query.order.map((o=>o.key)).filter((key=>key!==filter.key));const beneficialIndexes=indexesOnKey.map((index=>{const availableKeys=index.includeKeys.concat(index.key);const forOtherFilters=availableKeys.filter((key=>otherFilterKeys.indexOf(key)>=0));const forSorting=availableKeys.filter((key=>sortKeys.indexOf(key)>=0));const forBoth=forOtherFilters.concat(forSorting.filter((index=>forOtherFilters.indexOf(index)<0)));const points={filters:forOtherFilters.length,sorting:forSorting.length*(query.take!==0?forSorting.length:1),both:forBoth.length*forBoth.length,get total(){return this.filters+this.sorting+this.both}};return{index:index,points:points.total,filterKeys:forOtherFilters,sortKeys:forSorting}}));beneficialIndexes.sort(((a,b)=>a.points>b.points?-1:1));const bestBenificialIndex=beneficialIndexes[0];filter.index=bestBenificialIndex.index;bestBenificialIndex.filterKeys.forEach((key=>{query.filters.filter((f=>f!==filter&&f.key===key)).forEach((f=>{if(!DataIndex.validOperators.includes(f.op)){return}f.indexUsage="filter";f.index=bestBenificialIndex.index}))}));bestBenificialIndex.sortKeys.forEach((key=>{query.order.filter((s=>s.key===key)).forEach((s=>{s.index=bestBenificialIndex.index}))}))}if(filter.index){usingIndexes.push({index:filter.index,description:filter.index.description})}}));if(query.order.length>0&&query.take!==0){query.order.forEach((sort=>{if(sort.index){return}sort.index=availableIndexes.filter((index=>index.key===sort.key)).find((index=>index.type==="normal"))}))}const indexDescriptions=usingIndexes.map((index=>index.description)).join(", ");usingIndexes.length>0&&this.storage.debug.log(`Using indexes for query: ${indexDescriptions}`);const tableScanFilters=query.filters.filter((filter=>!filter.index));const specialOpsRegex=/^[a-z]+:/i;if(tableScanFilters.some((filter=>specialOpsRegex.test(filter.op)))){const f=tableScanFilters.find((filter=>specialOpsRegex.test(filter.op)));const err=new Error(`query contains operator "${f.op}" which requires a special index that was not found on path "${path}", key "${f.key}"`);return Promise.reject(err)}const allowedTableScanOperators=["<","<=","==","!=",">=",">","like","!like","in","!in","matches","!matches","between","!between","has","!has","contains","!contains","exists","!exists"];for(let i=0;i<tableScanFilters.length;i++){const f=tableScanFilters[i];if(!allowedTableScanOperators.includes(f.op)){return Promise.reject(new Error(`query contains unknown filter operator "${f.op}" on path "${path}", key "${f.key}"`))}}if(isWildcardPath&&tableScanFilters.length>0){const keys=tableScanFilters.reduce(((keys,f)=>{if(keys.indexOf(f.key)<0){keys.push(f.key)}return keys}),[]).map((key=>`"${key}"`));const err=new Error(`This wildcard path query on "/${path}" requires index(es) on key(s): ${keys.join(", ")}. Create the index(es) and retry`);return Promise.reject(err)}const indexScanPromises=[];query.filters.forEach((filter=>{if(filter.index&&filter.indexUsage!=="filter"){let promise=filter.index.query(filter.op,filter.compare).then((results=>{options.eventHandler&&options.eventHandler({name:"stats",type:"index_query",source:filter.index.description,stats:results.stats});if(results.hints.length>0){options.eventHandler&&options.eventHandler({name:"hints",type:"index_query",source:filter.index.description,hints:results.hints})}return results}));const resultFilters=query.filters.filter((f=>f.index===filter.index&&f.indexUsage==="filter"));if(resultFilters.length>0){promise=promise.then((results=>{resultFilters.forEach((filter=>{let{key:key,op:op,compare:compare,index:index}=filter;if(typeof compare==="string"&&!index.caseSensitive){compare=compare.toLocaleLowerCase(index.textLocale)}results=results.filterMetadata(key,op,compare)}));return results}))}indexScanPromises.push(promise)}}));const stepsExecuted={filtered:query.filters.length===0,skipped:query.skip===0,taken:query.take===0,sorted:query.order.length===0,preDataLoaded:false,dataLoaded:false};if(query.filters.length===0&&query.take===0){this.storage.debug.warn(`Filterless queries must use .take to limit the results. Defaulting to 100 for query on path "${path}"`);query.take=100}if(query.filters.length===0&&query.order.length>0&&query.order[0].index){const sortIndex=query.order[0].index;this.storage.debug.log(`Using index for sorting: ${sortIndex.description}`);let ascending=query.take<0?!query.order[0].ascending:query.order[0].ascending;const promise=sortIndex.take(query.skip,Math.abs(query.take),ascending).then((results=>{options.eventHandler&&options.eventHandler({name:"stats",type:"sort_index_take",source:sortIndex.description,stats:results.stats});if(results.hints.length>0){options.eventHandler&&options.eventHandler({name:"hints",type:"sort_index_take",source:sortIndex.description,hints:results.hints})}return results}));indexScanPromises.push(promise);stepsExecuted.skipped=true;stepsExecuted.taken=true;stepsExecuted.sorted=true}return Promise.all(indexScanPromises).then((indexResultSets=>{let indexedResults=[];if(indexResultSets.length===1){const resultSet=indexResultSets[0];indexedResults=resultSet.map((match=>{const result={key:match.key,path:match.path,val:{[resultSet.filterKey]:match.value}};match.metadata&&Object.assign(result.val,match.metadata);return result}));stepsExecuted.filtered=true}else if(indexResultSets.length>1){indexResultSets.sort(((a,b)=>a.length<b.length?-1:1));const shortestSet=indexResultSets[0];const otherSets=indexResultSets.slice(1);indexedResults=shortestSet.reduce(((results,match)=>{const result={key:match.key,path:match.path,val:{[shortestSet.filterKey]:match.value}};const matchedInAllSets=otherSets.every((set=>set.findIndex((m=>m.path===match.path))>=0));if(matchedInAllSets){match.metadata&&Object.assign(result.val,match.metadata);otherSets.forEach((set=>{const otherResult=set.find((r=>r.path===result.path));result.val[set.filterKey]=otherResult.value;otherResult.metadata&&Object.assign(result.val,otherResult.metadata)}));results.push(result)}return results}),[]);stepsExecuted.filtered=true}if(isWildcardPath||indexScanPromises.length>0&&tableScanFilters.length===0){if(query.order.length===0||query.order.every((o=>o.index))){stepsExecuted.preDataLoaded=true;if(!stepsExecuted.sorted&&query.order.length>0){sortMatches(indexedResults)}stepsExecuted.sorted=true;if(!stepsExecuted.skipped&&query.skip>0){indexedResults=query.take<0?indexedResults.slice(0,-query.skip):indexedResults.slice(query.skip)}if(!stepsExecuted.taken&&query.take!==0){indexedResults=query.take<0?indexedResults.slice(query.take):indexedResults.slice(0,query.take)}stepsExecuted.skipped=true;stepsExecuted.taken=true;if(!options.snapshots){return indexedResults}const childOptions={include:options.include,exclude:options.exclude,child_objects:options.child_objects};return loadResultsData(indexedResults,childOptions).then((results=>{stepsExecuted.dataLoaded=true;return results}))}if(options.snapshots||!stepsExecuted.sorted){const loadPartialResults=query.order.length>0;const childOptions=loadPartialResults?{include:query.order.map((order=>order.key))}:{include:options.include,exclude:options.exclude,child_objects:options.child_objects};return loadResultsData(indexedResults,childOptions).then((results=>{if(query.order.length>0){sortMatches(results)}stepsExecuted.sorted=true;if(query.skip>0){results=results.take<0?results.slice(0,-query.skip):results.slice(query.skip)}if(query.take!==0){results=query.take<0?results.slice(query.take):results.slice(0,query.take)}stepsExecuted.skipped=true;stepsExecuted.taken=true;if(options.snapshots&&loadPartialResults){return loadResultsData(results,{include:options.include,exclude:options.exclude,child_objects:options.child_objects})}return results}))}else{return indexedResults}}let indexKeyFilter;if(indexedResults.length>0){indexKeyFilter=indexedResults.map((result=>result.key))}const promises=[];let matches=[];let preliminaryStop=false;const loadPartialData=query.order.length>0;const childOptions=loadPartialData?{include:query.order.map((order=>order.key))}:{include:options.include,exclude:options.exclude,child_objects:options.child_objects};return Node.getChildren(this.storage,path,indexKeyFilter).next((child=>{if(child.type===Node.VALUE_TYPES.OBJECT){if(!child.address){return}if(preliminaryStop){return false}const p=Node.matches(this.storage,child.address.path,tableScanFilters).then((isMatch=>{if(!isMatch){return null}const childPath=child.address.path;if(options.snapshots||query.order.length>0){return Node.getValue(this.storage,childPath,childOptions).then((val=>({path:childPath,val:val})))}else{return{path:childPath}}})).then((result=>{if(result!==null){matches.push(result);if(query.take!==0&&matches.length>Math.abs(query.take)+query.skip){if(query.order.length>0){sortMatches(matches)}else if(query.take>0){preliminaryStop=true}if(query.take<0){matches.shift()}else{matches.pop()}}}}));promises.push(p)}})).catch((reason=>{if(!(reason instanceof NodeNotFoundError)){this.storage.debug.warn(`Error getting child stream: ${reason}`)}return[]})).then((()=>Promise.all(promises).then((()=>{stepsExecuted.preDataLoaded=loadPartialData;stepsExecuted.dataLoaded=!loadPartialData;if(query.order.length>0){sortMatches(matches)}stepsExecuted.sorted=true;if(query.skip>0){matches=query.take<0?matches.slice(0,-query.skip):matches.slice(query.skip)}stepsExecuted.skipped=true;if(query.take!==0){matches=query.take<0?matches.slice(query.take):matches.slice(0,query.take)}stepsExecuted.taken=true;if(!stepsExecuted.dataLoaded){return loadResultsData(matches,{include:options.include,exclude:options.exclude,child_objects:options.child_objects}).then((results=>{stepsExecuted.dataLoaded=true;return results}))}return matches}))))})).then((matches=>{if(!stepsExecuted.sorted&&query.order.length>0){sortMatches(matches)}if(!options.snapshots){matches=matches.map((match=>match.path))}if(!stepsExecuted.skipped&&query.skip>0){matches=query.take<0?matches.slice(0,-query.skip):matches.slice(query.skip)}if(!stepsExecuted.taken&&query.take!==0){matches=query.take<0?matches.slice(query.take):matches.slice(0,query.take)}if(options.monitor===true){options.monitor={add:true,change:true,remove:true}}if(typeof options.monitor==="object"&&(options.monitor.add||options.monitor.change||options.monitor.remove)){const matchedPaths=options.snapshots?matches.map((match=>match.path)):matches.slice();const ref=this.db.ref(path);const removeMatch=path=>{const index=matchedPaths.indexOf(path);if(index<0){return}matchedPaths.splice(index,1)};const addMatch=path=>{if(matchedPaths.includes(path)){return}matchedPaths.push(path)};const stopMonitoring=()=>{this.unsubscribe(ref.path,"child_changed",childChangedCallback);this.unsubscribe(ref.path,"child_added",childAddedCallback);this.unsubscribe(ref.path,"notify_child_removed",childRemovedCallback)};const childChangedCallback=(err,path,newValue,oldValue)=>{const wasMatch=matchedPaths.includes(path);let keepMonitoring=true;const checkKeys=[];query.filters.forEach((f=>!checkKeys.includes(f.key)&&checkKeys.push(f.key)));const seenKeys=[];typeof oldValue==="object"&&Object.keys(oldValue).forEach((key=>!seenKeys.includes(key)&&seenKeys.push(key)));typeof newValue==="object"&&Object.keys(newValue).forEach((key=>!seenKeys.includes(key)&&seenKeys.push(key)));const missingKeys=[];let isMatch=seenKeys.every((key=>{if(!checkKeys.includes(key)){return true}const filters=query.filters.filter((filter=>filter.key===key));return filters.every((filter=>{if(allowedTableScanOperators.includes(filter.op)){return this.storage.test(newValue[key],filter.op,filter.compare)}if(filter.index.constructor.name==="FullTextDataIndex"&&filter.index.localeKey&&!seenKeys.includes(filter.index.localeKey)){missingKeys.push(filter.index.localeKey);return true}return filter.index.test(newValue,filter.op,filter.compare)}))}));if(isMatch){missingKeys.push(...checkKeys.filter((key=>!seenKeys.includes(key))));let promise=Promise.resolve(true);if(!wasMatch&&missingKeys.length>0){const filterQueue=query.filters.filter((f=>missingKeys.includes(f.key)));const simpleFilters=filterQueue.filter((f=>allowedTableScanOperators.includes(f.op)));const indexFilters=filterQueue.filter((f=>!allowedTableScanOperators.includes(f.op)));const processFilters=()=>{const checkIndexFilters=()=>{const keysToLoad=indexFilters.reduce(((keys,filter)=>{if(!keys.includes(filter.key)){keys.push(filter.key)}if(filter.index.constructor.name==="FullTextDataIndex"&&filter.index.localeKey&&!keys.includes(filter.index.localeKey)){keys.push(filter.index.localeKey)}return keys}),[]);return Node.getValue(this.storage,path,{include:keysToLoad}).then((val=>{if(val===null){return false}return indexFilters.every((filter=>filter.index.test(val,filter.op,filter.compare)))}))};if(simpleFilters.length>0){return Node.matches(this.storage,path,simpleFilters).then((isMatch=>{if(isMatch){if(indexFilters.length===0){return true}return checkIndexFilters()}return false}))}else{return checkIndexFilters()}};promise=processFilters()}return promise.then((isMatch=>{if(isMatch){if(!wasMatch){addMatch(path)}let gotValue=value=>{if(wasMatch&&options.monitor.change){keepMonitoring=options.eventHandler({name:"change",path:path,value:value})}else if(!wasMatch&&options.monitor.add){keepMonitoring=options.eventHandler({name:"add",path:path,value:value})}if(keepMonitoring===false){stopMonitoring()}};if(options.snapshots){const loadOptions={include:options.include,exclude:options.exclude,child_objects:options.child_objects};return this.storage.getNodeValue(path,loadOptions).then(gotValue)}else{return gotValue(newValue)}}else if(wasMatch){removeMatch(path);if(options.monitor.remove){keepMonitoring=options.eventHandler({name:"remove",path:path,value:oldValue})}}if(keepMonitoring===false){stopMonitoring()}}))}else{if(wasMatch){removeMatch(path);if(options.monitor.remove){keepMonitoring=options.eventHandler({name:"remove",path:path,value:oldValue});if(keepMonitoring===false){stopMonitoring()}}}}};const childAddedCallback=(err,path,newValue,oldValue)=>{let isMatch=query.filters.every((filter=>{if(allowedTableScanOperators.includes(filter.op)){return this.storage.test(newValue[filter.key],filter.op,filter.compare)}else{return filter.index.test(newValue,filter.op,filter.compare)}}));let keepMonitoring=true;if(isMatch){addMatch(path);if(options.monitor.add){keepMonitoring=options.eventHandler({name:"add",path:path,value:options.snapshots?newValue:null})}}if(keepMonitoring===false){stopMonitoring()}};const childRemovedCallback=(err,path,newValue,oldValue)=>{let keepMonitoring=true;removeMatch(path);if(options.monitor.remove){keepMonitoring=options.eventHandler({name:"remove",path:path,value:options.snapshots?oldValue:null})}if(keepMonitoring===false){stopMonitoring()}};if(options.monitor.add||options.monitor.change||options.monitor.remove){this.subscribe(ref.path,"child_changed",childChangedCallback)}if(options.monitor.remove){this.subscribe(ref.path,"notify_child_removed",childRemovedCallback)}if(options.monitor.add){this.subscribe(ref.path,"child_added",childAddedCallback)}}return{results:matches,context:context}}))}createIndex(path,key,options){return this.storage.indexes.create(path,key,options)}getIndexes(){return Promise.resolve(this.storage.indexes.list())}async reflect(path,type,args){args=args||{};const getChildren=async(path,limit=50,skip=0,from=null)=>{if(typeof limit==="string"){limit=parseInt(limit)}if(typeof skip==="string"){skip=parseInt(skip)}if(["null","undefined"].includes(from)){from=null}const children=[];let n=0,stop=false,more=false;await Node.getChildren(this.storage,path).next((childInfo=>{if(stop){more=true;return false}n++;const include=from!==null?childInfo.key>from:skip===0||n>skip;if(include){children.push({key:typeof childInfo.key==="string"?childInfo.key:childInfo.index,type:childInfo.valueTypeName,value:childInfo.value,address:typeof childInfo.address==="object"&&"pageNr"in childInfo.address?{pageNr:childInfo.address.pageNr,recordNr:childInfo.address.recordNr}:undefined})}stop=limit>0&&children.length===limit})).catch((err=>{}));return{more:more,list:children}};switch(type){case"children":{return getChildren(path,args.limit,args.skip,args.from)}case"info":{const info={key:"",exists:false,type:"unknown",value:undefined,children:{count:0,more:false,list:[]}};const nodeInfo=await Node.getInfo(this.storage,path,{include_child_count:args.child_count===true});info.key=typeof nodeInfo.key!=="undefined"?nodeInfo.key:nodeInfo.index;info.exists=nodeInfo.exists;info.type=nodeInfo.valueTypeName;info.value=nodeInfo.value;let isObjectOrArray=nodeInfo.exists&&nodeInfo.address&&[Node.VALUE_TYPES.OBJECT,Node.VALUE_TYPES.ARRAY].includes(nodeInfo.type);if(args.child_count===true){info.children={count:isObjectOrArray?nodeInfo.childCount:0}}else if(typeof args.child_limit==="number"&&args.child_limit>0){if(isObjectOrArray){info.children=await getChildren(path,args.child_limit,args.child_skip,args.child_from)}}return info}}}export(path,stream,options={format:"json"}){return this.storage.exportNode(path,stream,options)}import(path,read,options={format:"json",suppress_events:false,method:"set"}){return this.storage.importNode(path,read,options)}async setSchema(path,schema){return this.storage.setSchema(path,schema)}async getSchema(path){return this.storage.getSchema(path)}async getSchemas(){return this.storage.getSchemas()}async validateSchema(path,value,isUpdate){return this.storage.validateSchema(path,value,{updates:isUpdate})}async getMutations(filter){if(typeof this.storage.getMutations!=="function"){throw new Error("Used storage type does not support getMutations")}if(typeof filter!=="object"){throw new Error("No filter specified")}if(typeof filter.cursor!=="string"&&typeof filter.timestamp!=="number"){throw new Error("No cursor or timestamp given")}return this.storage.getMutations(filter)}async getChanges(filter){if(typeof this.storage.getChanges!=="function"){throw new Error("Used storage type does not support getChanges")}if(typeof filter!=="object"){throw new Error("No filter specified")}if(typeof filter.cursor!=="string"&&typeof filter.timestamp!=="number"){throw new Error("No cursor or timestamp given")}return this.storage.getChanges(filter)}}module.exports={LocalApi:LocalApi}},{"./data-index":37,"./node":36,"./storage":40,"./storage-acebase":37,"./storage-custom":39,"./storage-mssql":37,"./storage-sqlite":37,"acebase-core":12}],30:[function(require,module,exports){const{DataReference:DataReference,DataSnapshot:DataSnapshot,EventSubscription:EventSubscription,PathReference:PathReference,TypeMappings:TypeMappings,ID:ID,proxyAccess:proxyAccess}=require("acebase-core");const{AceBaseLocalSettings:AceBaseLocalSettings}=require("./acebase-local");const{BrowserAceBase:BrowserAceBase}=require("./acebase-browser");const{CustomStorageSettings:CustomStorageSettings,CustomStorageTransaction:CustomStorageTransaction,CustomStorageHelpers:CustomStorageHelpers}=require("./storage-custom");const acebase={AceBase:BrowserAceBase,AceBaseLocalSettings:AceBaseLocalSettings,DataReference:DataReference,DataSnapshot:DataSnapshot,EventSubscription:EventSubscription,PathReference:PathReference,TypeMappings:TypeMappings,CustomStorageSettings:CustomStorageSettings,CustomStorageTransaction:CustomStorageTransaction,CustomStorageHelpers:CustomStorageHelpers,ID:ID,proxyAccess:proxyAccess};window.acebase=acebase;window.AceBase=BrowserAceBase;module.exports=acebase},{"./acebase-browser":27,"./acebase-local":28,"./storage-custom":39,"acebase-core":12}],31:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.IPCPeer=void 0;const acebase_core_1=require("acebase-core");const ipc_1=require("./ipc");class IPCPeer extends ipc_1.AceBaseIPCPeer{constructor(storage){super(storage,acebase_core_1.ID.generate());this.masterPeerId=this.id;this.ipcType="browser.bcc";window.addEventListener("beforeunload",(()=>{this.exit()}));if(typeof window.BroadcastChannel!=="undefined"){this.channel=new BroadcastChannel(`acebase:${storage.name}`)}else{const listeners=[null];const notImplemented=()=>{throw new Error("Not implemented")};this.channel={name:`acebase:${storage.name}`,postMessage:message=>{const messageId=acebase_core_1.ID.generate(),key=`acebase:${storage.name}:${this.id}:${messageId}`,payload=JSON.stringify(acebase_core_1.Transport.serialize(message));localStorage.setItem(key,payload);setTimeout((()=>localStorage.removeItem(key)),10)},set onmessage(handler){listeners[0]=handler},set onmessageerror(handler){notImplemented()},close(){notImplemented()},addEventListener(event,callback){if(event!=="message"){notImplemented()}listeners.push(callback)},removeEventListener(event,callback){const i=listeners.indexOf(callback);i>=1&&listeners.splice(i,1)},dispatchEvent(event){listeners.forEach((callback=>{try{callback&&callback(event)}catch(err){console.error(err)}}));return true}};window.addEventListener("storage",(event=>{const[acebase,dbname,peerId,messageId]=event.key.split(":");if(acebase!=="acebase"||dbname!==storage.name||peerId===this.id||event.newValue===null){return}const message=acebase_core_1.Transport.deserialize(JSON.parse(event.newValue));this.channel.dispatchEvent({data:message})}))}this.channel.addEventListener("message",(async event=>{const message=event.data;if(message.to&&message.to!==this.id){return}storage.debug.verbose(`[BroadcastChannel] received: `,message);if(message.type==="hello"&&message.from<this.masterPeerId){this.masterPeerId=message.from;storage.debug.log(`[BroadcastChannel] Tab ${this.masterPeerId} is the master.`)}else if(message.type==="bye"&&message.from===this.masterPeerId){storage.debug.log(`[BroadcastChannel] Master tab ${this.masterPeerId} is leaving`);const allPeerIds=this.peers.map((peer=>peer.id)).concat(this.id).filter((id=>id!==this.masterPeerId));this.masterPeerId=allPeerIds.sort()[0];storage.debug.log(`[BroadcastChannel] ${this.masterPeerId===this.id?"We are":`tab ${this.masterPeerId} is`} the new master. Requesting ${this._locks.length} locks (${this._locks.filter((r=>!r.granted)).length} pending)`);const requests=this._locks.splice(0);await Promise.all(requests.filter((req=>req.granted)).map((async req=>{let released,movedToParent;req.lock.release=()=>new Promise((resolve=>released=resolve));req.lock.moveToParent=()=>new Promise((resolve=>movedToParent=resolve));const lock=await this.lock({path:req.lock.path,write:req.lock.forWriting,tid:req.lock.tid,comment:req.lock.comment});if(movedToParent){const newLock=await lock.moveToParent();movedToParent(newLock)}if(released){await lock.release();released()}})));await Promise.all(requests.filter((req=>!req.granted)).map((async req=>{await this.lock(req.request)})))}return this.handleMessage(message)}));const helloMsg={type:"hello",from:this.id,data:undefined};this.sendMessage(helloMsg)}sendMessage(message){this.storage.debug.verbose(`[BroadcastChannel] sending: `,message);this.channel.postMessage(message)}}exports.IPCPeer=IPCPeer},{"./ipc":32,"acebase-core":12}],32:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AceBaseIPCPeer=exports.AceBaseIPCPeerExitingError=void 0;const acebase_core_1=require("acebase-core");const node_lock_1=require("../node-lock");class AceBaseIPCPeerExitingError extends Error{constructor(message){super(`Exiting: ${message}`)}}exports.AceBaseIPCPeerExitingError=AceBaseIPCPeerExitingError;class AceBaseIPCPeer extends acebase_core_1.SimpleEventEmitter{constructor(storage,id,dbname=storage.name){super();this.storage=storage;this.id=id;this.dbname=dbname;this.ipcType="ipc";this.ourSubscriptions=[];this.remoteSubscriptions=[];this.peers=[];this._exiting=false;this._locks=[];this._requests=new Map;this._eventsEnabled=true;this._nodeLocker=new node_lock_1.NodeLocker(storage.debug,storage.settings.lockTimeout);storage.on("subscribe",(subscription=>{storage.debug.verbose(`database subscription being added on peer ${this.id}`);const remoteSubscription=this.remoteSubscriptions.find((sub=>sub.callback===subscription.callback));if(remoteSubscription){return}const othersAlreadyNotifying=this.ourSubscriptions.some((sub=>sub.event===subscription.event&&sub.path===subscription.path));this.ourSubscriptions.push(subscription);if(othersAlreadyNotifying){return}const message={type:"subscribe",from:this.id,data:{path:subscription.path,event:subscription.event}};this.sendMessage(message)}));storage.on("unsubscribe",(subscription=>{const remoteSubscription=this.remoteSubscriptions.find((sub=>sub.callback===subscription.callback));if(remoteSubscription){this.remoteSubscriptions.splice(this.remoteSubscriptions.indexOf(remoteSubscription),1);return}this.ourSubscriptions.filter((sub=>sub.path===subscription.path&&(!subscription.event||sub.event===subscription.event)&&(!subscription.callback||sub.callback===subscription.callback))).forEach((sub=>{this.ourSubscriptions.splice(this.ourSubscriptions.indexOf(sub),1);const message={type:"unsubscribe",from:this.id,data:{path:sub.path,event:sub.event}};this.sendMessage(message)}))}))}get isMaster(){return this.masterPeerId===this.id}async exit(code=0){if(this._exiting){return this.once("exit")}this._exiting=true;this.storage.debug.warn(`Received ${this.isMaster?"master":"worker "+this.id} process exit request`);if(this._locks.length>0){this.storage.debug.warn(`Waiting for ${this.isMaster?"master":"worker"} ${this.id} locks to clear`);await this.once("locks-cleared")}this.sayGoodbye(this.id);this.storage.debug.warn(`${this.isMaster?"Master":"Worker "+this.id} will now exit`);this.emitOnce("exit",code)}sayGoodbye(forPeerId){const bye={type:"bye",from:forPeerId,data:undefined};this.sendMessage(bye)}addPeer(id,sendReply=true,ignoreDuplicate=false){if(this._exiting){return}const peer=this.peers.find((w=>w.id===id));if(!peer){this.peers.push({id:id,lastSeen:Date.now()})}if(sendReply){const helloMessage={type:"hello",from:this.id,to:id,data:undefined};this.sendMessage(helloMessage);this.ourSubscriptions.forEach((sub=>{const message={type:"subscribe",from:this.id,to:id,data:{path:sub.path,event:sub.event}};this.sendMessage(message)}))}}removePeer(id,ignoreUnknown=false){if(this._exiting){return}const peer=this.peers.find((peer=>peer.id===id));if(!peer){if(!ignoreUnknown){throw new Error(`We are supposed to know this peer!`)}return}this.peers.splice(this.peers.indexOf(peer),1);const subscriptions=this.remoteSubscriptions.filter((sub=>sub.for===id));subscriptions.forEach((sub=>{this.remoteSubscriptions.splice(this.remoteSubscriptions.indexOf(sub),1);this.storage.subscriptions.remove(sub.path,sub.event,sub.callback)}))}addRemoteSubscription(peerId,details){if(this._exiting){return}if(this.remoteSubscriptions.some((sub=>sub.for===peerId&&sub.event===details.event&&sub.path===details.path))){return}const subscribeCallback=(err,path,val,previous,context)=>{let eventMessage={type:"event",from:this.id,to:peerId,path:details.path,event:details.event,data:{path:path,val:val,previous:previous,context:context}};this.sendMessage(eventMessage)};this.remoteSubscriptions.push({for:peerId,event:details.event,path:details.path,callback:subscribeCallback});this.storage.subscriptions.add(details.path,details.event,subscribeCallback)}cancelRemoteSubscription(peerId,details){const sub=this.remoteSubscriptions.find((sub=>sub.for===peerId&&sub.event===details.event&&sub.path===details.event));if(!sub){return}this.storage.subscriptions.remove(details.path,details.event,sub.callback)}async handleMessage(message){switch(message.type){case"hello":return this.addPeer(message.from,message.to!==this.id,false);case"bye":return this.removePeer(message.from,true);case"subscribe":return this.addRemoteSubscription(message.from,message.data);case"unsubscribe":return this.cancelRemoteSubscription(message.from,message.data);case"event":{if(!this._eventsEnabled){break}const eventMessage=message;const context=eventMessage.data.context||{};context.acebase_ipc={type:this.ipcType,origin:eventMessage.from};const subscriptions=this.ourSubscriptions.filter((sub=>sub.event===eventMessage.event&&sub.path===eventMessage.path));subscriptions.forEach((sub=>{sub.callback(null,eventMessage.data.path,eventMessage.data.val,eventMessage.data.previous,context)}));break}case"lock-request":{if(!this.isMaster){throw new Error(`Workers are not supposed to receive lock requests!`)}const request=message;const result={type:"lock-result",id:request.id,from:this.id,to:request.from,ok:true,data:undefined};try{const lock=await this.lock(request.data);result.data={id:lock.id,path:lock.path,tid:lock.tid,write:lock.forWriting,expires:lock.expires,comment:lock.comment}}catch(err){result.ok=false;result.reason=err.stack||err.message||err}return this.sendMessage(result)}case"lock-result":{if(this.isMaster){throw new Error(`Masters are not supposed to receive results for lock requests!`)}const result=message;const request=this._requests.get(result.id);if(typeof request!=="object"){throw new Error(`The request must be known to us!`)}if(result.ok){request.resolve(result.data)}else{request.reject(new Error(result.reason))}return}case"unlock-request":{if(!this.isMaster){throw new Error(`Workers are not supposed to receive unlock requests!`)}const request=message;const result={type:"unlock-result",id:request.id,from:this.id,to:request.from,ok:true,data:{id:request.data.id}};try{const lockInfo=this._locks.find((l=>{var _a;return((_a=l.lock)===null||_a===void 0?void 0:_a.id)===request.data.id}));await lockInfo.lock.release()}catch(err){result.ok=false;result.reason=err.stack||err.message||err}return this.sendMessage(result)}case"unlock-result":{if(this.isMaster){throw new Error(`Masters are not supposed to receive results for unlock requests!`)}const result=message;const request=this._requests.get(result.id);if(typeof request!=="object"){throw new Error(`The request must be known to us!`)}if(result.ok){request.resolve(result.data)}else{request.reject(new Error(result.reason))}return}case"move-lock-request":{if(!this.isMaster){throw new Error(`Workers are not supposed to receive move lock requests!`)}const request=message;const result={type:"lock-result",id:request.id,from:this.id,to:request.from,ok:true,data:undefined};try{let movedLock;const lockRequest=this._locks.find((r=>{var _a;return((_a=r.lock)===null||_a===void 0?void 0:_a.id)===request.data.id}));if(request.data.move_to==="parent"){movedLock=await lockRequest.lock.moveToParent()}else{throw new Error(`Unknown lock move_to "${request.data.move_to}"`)}lockRequest.lock=movedLock;result.data={id:movedLock.id,path:movedLock.path,tid:movedLock.tid,write:movedLock.forWriting,expires:movedLock.expires,comment:movedLock.comment}}catch(err){result.ok=false;result.reason=err.stack||err.message||err}return this.sendMessage(result)}case"notification":{return this.emit("notification",message)}case"request":{return this.emit("request",message)}case"result":{const result=message;const request=this._requests.get(result.id);if(typeof request!=="object"){throw new Error(`Result of unknown request received`)}if(result.ok){request.resolve(result.data)}else{request.reject(new Error(result.reason))}}}}async lock(details){if(this._exiting){const tidApproved=this._locks.find((l=>l.tid===details.tid&&l.granted));if(!tidApproved){throw new AceBaseIPCPeerExitingError("new transaction lock denied because the IPC peer is exiting")}}const removeLock=lockDetails=>{this._locks.splice(this._locks.indexOf(lockDetails),1);if(this._locks.length===0){this.emit("locks-cleared")}};if(this.isMaster){const lockInfo={tid:details.tid,granted:false,request:details,lock:null};this._locks.push(lockInfo);const lock=await this._nodeLocker.lock(details.path,details.tid,details.write,details.comment);lockInfo.tid=lock.tid;lockInfo.granted=true;const createIPCLock=lock=>({get id(){return lock.id},get tid(){return lock.tid},get path(){return lock.path},get forWriting(){return lock.forWriting},get expires(){return lock.expires},get comment(){return lock.comment},get state(){return lock.state},release:async()=>{await lock.release();removeLock(lockInfo)},moveToParent:async()=>{const parentLock=await lock.moveToParent();lockInfo.lock=createIPCLock(parentLock);return lockInfo.lock}});lockInfo.lock=createIPCLock(lock);return lockInfo.lock}else{const lockInfo={tid:details.tid,granted:false,request:details,lock:null};this._locks.push(lockInfo);const createIPCLock=result=>{lockInfo.granted=true;lockInfo.tid=result.tid;lockInfo.lock={id:result.id,tid:result.tid,path:result.path,forWriting:result.write,expires:result.expires,comment:result.comment,release:async()=>{const req={type:"unlock-request",id:acebase_core_1.ID.generate(),from:this.id,to:this.masterPeerId,data:{id:lockInfo.lock.id}};const result=await this.request(req);this.storage.debug.verbose(`Worker ${this.id} released lock ${lockInfo.lock.id} (tid ${lockInfo.lock.tid}, ${lockInfo.lock.comment}, "/${lockInfo.lock.path}", ${lockInfo.lock.forWriting?"write":"read"})`);removeLock(lockInfo)},moveToParent:async()=>{const req={type:"move-lock-request",id:acebase_core_1.ID.generate(),from:this.id,to:this.masterPeerId,data:{id:lockInfo.lock.id,move_to:"parent"}};let result;try{result=await this.request(req)}catch(err){removeLock(lockInfo);throw err}lockInfo.lock=createIPCLock(result);return lockInfo.lock}};return lockInfo.lock};const req={type:"lock-request",id:acebase_core_1.ID.generate(),from:this.id,to:this.masterPeerId,data:details};let result,err;try{result=await this.request(req)}catch(e){err=e;result=null}if(err){removeLock(lockInfo);throw err}return createIPCLock(result)}}async request(req){let resolve,reject;const promise=new Promise(((rs,rj)=>{resolve=result=>{this._requests.delete(req.id);rs(result)};reject=err=>{this._requests.delete(req.id);rj(err)}}));this._requests.set(req.id,{resolve:resolve,reject:reject,request:req});this.sendMessage(req);return promise}sendRequest(request){const req={type:"request",from:this.id,to:this.masterPeerId,id:acebase_core_1.ID.generate(),data:request};return this.request(req).catch((err=>{this.storage.debug.error(err);throw err}))}replyRequest(requestMessage,result){const reply={type:"result",id:requestMessage.id,ok:true,from:this.id,to:requestMessage.from,data:result};this.sendMessage(reply)}sendNotification(notification){const msg={type:"notification",from:this.id,data:notification};this.sendMessage(msg)}get eventsEnabled(){return this._eventsEnabled}set eventsEnabled(enabled){this.storage.debug.log(`ipc events ${enabled?"enabled":"disabled"}`);this._eventsEnabled=enabled}}exports.AceBaseIPCPeer=AceBaseIPCPeer},{"../node-lock":34,"acebase-core":12}],33:[function(require,module,exports){const{getValueTypeName:getValueTypeName}=require("./node-value-types");const{PathInfo:PathInfo}=require("acebase-core");class NodeInfo{constructor(info){this.path=info.path;this.type=info.type;this.index=info.index;this.key=info.key;this.exists=info.exists;this.address=info.address;this.value=info.value;this.childCount=info.childCount;if(typeof this.path==="string"&&(typeof this.key==="undefined"&&typeof this.index==="undefined")){let pathInfo=PathInfo.get(this.path);if(typeof pathInfo.key==="number"){this.index=pathInfo.key}else{this.key=pathInfo.key}}if(typeof this.exists==="undefined"){this.exists=true}}get valueType(){return this.type}get valueTypeName(){return getValueTypeName(this.valueType)}toString(){if(!this.exists){return`"${this.path}" doesn't exist`}if(this.address){return`"${this.path}" is ${this.valueTypeName} stored at ${this.address.pageNr},${this.address.recordNr}`}else{return`"${this.path}" is ${this.valueTypeName} with value ${this.value}`}}}module.exports={NodeInfo:NodeInfo}},{"./node-value-types":35,"acebase-core":12}],34:[function(require,module,exports){const{PathInfo:PathInfo,ID:ID}=require("acebase-core");const DEBUG_MODE=false;const DEFAULT_LOCK_TIMEOUT=120;const LOCK_STATE={PENDING:"pending",LOCKED:"locked",EXPIRED:"expired",DONE:"done"};class NodeLocker{constructor(debug,lockTimeout=DEFAULT_LOCK_TIMEOUT){this._locks=[];this._lastTid=0;this._quit=undefined;this.debug=debug;this.timeout=lockTimeout*1e3}setTimeout(timeout){this.timeout=timeout*1e3}createTid(){return DEBUG_MODE?++this._lastTid:ID.generate()}_allowLock(path,tid,forWriting){const conflict=this._locks.find((otherLock=>otherLock.tid!==tid&&otherLock.state===LOCK_STATE.LOCKED&&(forWriting||otherLock.forWriting)));return{allow:!conflict,conflict:conflict}}quit(){return new Promise((resolve=>{if(this._locks.length===0){return resolve()}this._quit=resolve}))}_rejectLock(lock,err){this._locks.splice(this._locks.indexOf(lock),1);clearTimeout(lock.timeout);try{lock.reject(err)}catch(err){console.error(`Unhandled promise rejection:`,err)}}_processLockQueue(){if(this._quit){const quitError=new Error("Quitting");this._locks.filter((lock=>lock.state===LOCK_STATE.PENDING)).forEach((lock=>this._rejectLock(lock,quitError)));if(this._locks.length===0){this._quit()}}const pending=this._locks.filter((lock=>lock.state===LOCK_STATE.PENDING)).sort(((a,b)=>{if(a.priority&&!b.priority){return-1}else if(!a.priority&&b.priority){return 1}return a.requested-b.requested}));pending.forEach((lock=>{const check=this._allowLock(lock.path,lock.tid,lock.forWriting);lock.waitingFor=check.conflict||null;if(check.allow){this.lock(lock).then(lock.resolve).catch((err=>this._rejectLock(lock,err)))}}))}async lock(path,tid,forWriting=true,comment="",options={withPriority:false,noTimeout:false}){let lock,proceed;if(path instanceof NodeLock){lock=path;proceed=true}else if(this._locks.findIndex((l=>l.tid===tid&&l.state===LOCK_STATE.EXPIRED))>=0){throw new Error(`lock on tid ${tid} has expired, not allowed to continue`)}else if(this._quit&&!options.withPriority){throw new Error(`Quitting`)}else{DEBUG_MODE&&console.error(`${forWriting?"write":"read"} lock requested on "${path}" by tid ${tid} (${comment})`);lock=new NodeLock(this,path,tid,forWriting,options.withPriority===true);lock.comment=comment;this._locks.push(lock);const check=this._allowLock(path,tid,forWriting);lock.waitingFor=check.conflict||null;proceed=check.allow}if(proceed){DEBUG_MODE&&console.error(`${lock.forWriting?"write":"read"} lock ALLOWED on "${lock.path}" by tid ${lock.tid} (${lock.comment})`);lock.state=LOCK_STATE.LOCKED;if(typeof lock.granted==="number"){}else{lock.granted=Date.now();if(options.noTimeout!==true){lock.expires=Date.now()+this.timeout;let timeoutCount=0;const timeoutHandler=()=>{if(lock.state!==LOCK_STATE.LOCKED){return}timeoutCount++;if(timeoutCount<=3){this.debug.warn(`${lock.forWriting?"write":"read"} lock on path "/${lock.path}" by tid ${lock.tid} (${lock.comment}) is taking a long time to complete [${timeoutCount}]`);lock.timeout=setTimeout(timeoutHandler,this.timeout/4);return}this.debug.error(`lock :: ${lock.forWriting?"write":"read"} lock on path "/${lock.path}" by tid ${lock.tid} (${lock.comment}) took too long`);lock.state=LOCK_STATE.EXPIRED;this._processLockQueue()};lock.timeout=setTimeout(timeoutHandler,this.timeout/4)}}return lock}else{console.assert(lock.state===LOCK_STATE.PENDING);const p=new Promise(((resolve,reject)=>{lock.resolve=resolve;lock.reject=reject}));return p}}unlock(lockOrId,comment,processQueue=true){let lock,i;if(lockOrId instanceof NodeLock){lock=lockOrId;i=this._locks.indexOf(lock)}else{let id=lockOrId;i=this._locks.findIndex((l=>l.id===id));lock=this._locks[i]}if(i<0){const msg=`lock on "/${lock.path}" for tid ${lock.tid} wasn't found; ${comment}`;throw new Error(msg)}lock.state=LOCK_STATE.DONE;clearTimeout(lock.timeout);this._locks.splice(i,1);DEBUG_MODE&&console.error(`${lock.forWriting?"write":"read"} lock RELEASED on "${lock.path}" by tid ${lock.tid}`);processQueue&&this._processLockQueue();return lock}list(){return this._locks||[]}isAllowed(path,tid,forWriting){return this._allowLock(path,tid,forWriting).allow}}let lastid=0;class NodeLock{static get LOCK_STATE(){return LOCK_STATE}constructor(locker,path,tid,forWriting,priority=false){this.locker=locker;this.path=path;this.tid=tid;this.forWriting=forWriting;this.priority=priority;this.state=LOCK_STATE.PENDING;this.requested=Date.now();this.granted=undefined;this.expires=undefined;this.comment="";this.waitingFor=null;this.id=++lastid;this.history=[]}async release(comment){this.history.push({action:"release",path:this.path,forWriting:this.forWriting,comment:comment});return this.locker.unlock(this,comment||this.comment)}async moveToParent(){const parentPath=PathInfo.get(this.path).parentPath;const allowed=this.locker.isAllowed(parentPath,this.tid,this.forWriting);if(allowed){DEBUG_MODE&&console.error(`moveToParent ALLOWED for ${this.forWriting?"write":"read"} lock on "${this.path}" by tid ${this.tid} (${this.comment})`);this.history.push({path:this.path,forWriting:this.forWriting,action:"moving to parent"});this.waitingFor=null;this.path=parentPath;return this}else{DEBUG_MODE&&console.error(`moveToParent QUEUED for ${this.forWriting?"write":"read"} lock on "${this.path}" by tid ${this.tid} (${this.comment})`);this.locker.unlock(this,`moveLockToParent: ${this.comment}`,false);const newLock=await this.locker.lock(parentPath,this.tid,this.forWriting,this.comment,{withPriority:true});DEBUG_MODE&&console.error(`QUEUED moveToParent ALLOWED for ${this.forWriting?"write":"read"} lock on "${this.path}" by tid ${this.tid} (${this.comment})`);newLock.history=this.history;newLock.history.push({path:this.path,forWriting:this.forWriting,action:"moving to parent through queue (priority)"});return newLock}}moveTo(otherPath,forWriting){const allowed=this.locker.isAllowed(otherPath,this.tid,forWriting);if(allowed){this.history.push({path:this.path,forWriting:this.forWriting,action:`moving to "${otherPath}"`});this.waitingFor=null;this.path=otherPath;this.forWriting=forWriting;return Promise.resolve(this)}else{this.locker.unlock(this,`moving to "/${otherPath}": ${this.comment}`,false);return this.locker.lock(otherPath,this.tid,forWriting,this.comment,{withPriority:true}).then((newLock=>{newLock.history=this.history;newLock.history.push({path:this.path,forWriting:this.forWriting,action:`moved to "${otherPath}" through queue`});return newLock}))}}}module.exports={NodeLocker:NodeLocker,NodeLock:NodeLock}},{"acebase-core":12}],35:[function(require,module,exports){const{PathReference:PathReference}=require("acebase-core");const VALUE_TYPES={OBJECT:1,ARRAY:2,NUMBER:3,BOOLEAN:4,STRING:5,DATETIME:6,BINARY:8,REFERENCE:9};function getValueTypeName(valueType){switch(valueType){case VALUE_TYPES.ARRAY:return"array";case VALUE_TYPES.BINARY:return"binary";case VALUE_TYPES.BOOLEAN:return"boolean";case VALUE_TYPES.DATETIME:return"date";case VALUE_TYPES.NUMBER:return"number";case VALUE_TYPES.OBJECT:return"object";case VALUE_TYPES.REFERENCE:return"reference";case VALUE_TYPES.STRING:return"string";default:"unknown"}}function getNodeValueType(value){if(value instanceof Array){return VALUE_TYPES.ARRAY}else if(value instanceof PathReference){return VALUE_TYPES.REFERENCE}else if(value instanceof ArrayBuffer){return VALUE_TYPES.BINARY}else if(typeof value==="string"){return VALUE_TYPES.STRING}else if(typeof value==="object"){return VALUE_TYPES.OBJECT}throw new Error(`Invalid value for standalone node: ${value}`)}function getValueType(value){if(value instanceof Array){return VALUE_TYPES.ARRAY}else if(value instanceof PathReference){return VALUE_TYPES.REFERENCE}else if(value instanceof ArrayBuffer){return VALUE_TYPES.BINARY}else if(value instanceof Date){return VALUE_TYPES.DATETIME}else if(typeof value==="string"){return VALUE_TYPES.STRING}else if(typeof value==="object"){return VALUE_TYPES.OBJECT}else if(typeof value==="number"){return VALUE_TYPES.NUMBER}else if(typeof value==="boolean"){return VALUE_TYPES.BOOLEAN}throw new Error(`Unknown value type: ${value}`)}module.exports={VALUE_TYPES:VALUE_TYPES,getValueTypeName:getValueTypeName,getNodeValueType:getNodeValueType,getValueType:getValueType}},{"acebase-core":12}],36:[function(require,module,exports){const{Storage:Storage}=require("./storage");const{NodeInfo:NodeInfo}=require("./node-info");const{VALUE_TYPES:VALUE_TYPES}=require("./node-value-types");class Node{static get VALUE_TYPES(){return VALUE_TYPES}static async getInfo(storage,path,options={no_cache:false,include_child_count:false}){const cacheable=options&&!options.no_cache&&!options.include_child_count;if(cacheable){let cachedInfo=storage.nodeCache.find(path);if(cachedInfo){return cachedInfo}}const info=await storage.getNodeInfo(path,{include_child_count:options.include_child_count});if(cacheable){storage.nodeCache.update(info)}return info}static update(storage,path,value,options={merge:true,suppress_events:false,context:null}){if(options.merge){return storage.updateNode(path,value,{suppress_events:options.suppress_events,context:options.context})}else{return storage.setNode(path,value,{suppress_events:options.suppress_events,context:options.context})}}static async exists(storage,path){const nodeInfo=await storage.getNodeInfo(path);return nodeInfo.exists}static getValue(storage,path,options={include:undefined,exclude:undefined,child_objects:true}){if(!options){options={}}if(typeof options.include!=="undefined"&&!(options.include instanceof Array)){throw new TypeError(`options.include must be an array of key names`)}if(typeof options.exclude!=="undefined"&&!(options.exclude instanceof Array)){throw new TypeError(`options.exclude must be an array of key names`)}if(["undefined","boolean"].indexOf(typeof options.child_objects)<0){throw new TypeError(`options.child_objects must be a boolean`)}return storage.getNodeValue(path,options)}static getChildren(storage,path,keyFilter=undefined){return storage.getChildren(path,{keyFilter:keyFilter})}static set(storage,path,value,options={context:null}){return Node.update(storage,path,value,{merge:false,context:options.context})}static transaction(storage,path,callback,options={suppress_events:false,context:null}){return storage.transactNode(path,callback,{suppress_events:options.suppress_events,context:options.context})}static matches(storage,path,criteria,options){return storage.matchNode(path,criteria,options)}}class NodeChange{static get CHANGE_TYPE(){return{UPDATE:"update",DELETE:"delete",INSERT:"insert"}}constructor(keyOrIndex,changeType,oldValue,newValue){this.keyOrIndex=keyOrIndex;this.changeType=changeType;this.oldValue=oldValue;this.newValue=newValue}}class NodeChangeTracker{constructor(path){this.path=path;this._changes=[];this._oldValue=undefined;this._newValue=undefined}addDelete(keyOrIndex,oldValue){const change=new NodeChange(keyOrIndex,NodeChange.CHANGE_TYPE.DELETE,oldValue,null);this._changes.push(change);return change}addUpdate(keyOrIndex,oldValue,newValue){const change=new NodeChange(keyOrIndex,NodeChange.CHANGE_TYPE.UPDATE,oldValue,newValue);this._changes.push(change);return change}addInsert(keyOrIndex,newValue){const change=new NodeChange(keyOrIndex,NodeChange.CHANGE_TYPE.INSERT,null,newValue);this._changes.push(change);return change}add(keyOrIndex,currentValue,newValue){if(currentValue===null){if(newValue===null){throw new Error(`Wrong logic for node change on "${this.nodeInfo.path}/${keyOrIndex}" - both old and new values are null`)}return this.addInsert(keyOrIndex,newValue)}else if(newValue===null){return this.addDelete(keyOrIndex,currentValue)}else{return this.addUpdate(keyOrIndex,currentValue,newValue)}}get updates(){return this._changes.filter((change=>change.changeType===NodeChange.CHANGE_TYPE.UPDATE))}get deletes(){return this._changes.filter((change=>change.changeType===NodeChange.CHANGE_TYPE.DELETE))}get inserts(){return this._changes.filter((change=>change.changeType===NodeChange.CHANGE_TYPE.INSERT))}get all(){return this._changes}get totalChanges(){return this._changes.length}get(keyOrIndex){return this._changes.find((change=>change.keyOrIndex===keyOrIndex))}hasChanged(keyOrIndex){return!!this.get(keyOrIndex)}get newValue(){if(typeof this._newValue==="object"){return this._newValue}if(typeof this._oldValue==="undefined"){throw new TypeError(`oldValue is not set`)}let newValue={};Object.keys(this.oldValue).forEach((key=>newValue[key]=this.oldValue[key]));this.deletes.forEach((change=>delete newValue[change.key]));this.updates.forEach((change=>newValue[change.key]=change.newValue));this.inserts.forEach((change=>newValue[change.key]=change.newValue));return newValue}set newValue(value){this._newValue=value}get oldValue(){if(typeof this._oldValue==="object"){return this._oldValue}if(typeof this._newValue==="undefined"){throw new TypeError(`newValue is not set`)}let oldValue={};Object.keys(this.newValue).forEach((key=>oldValue[key]=this.newValue[key]));this.deletes.forEach((change=>oldValue[change.key]=change.oldValue));this.updates.forEach((change=>oldValue[change.key]=change.oldValue));this.inserts.forEach((change=>delete oldValue[change.key]));return oldValue}set oldValue(value){this._oldValue=value}get typeChanged(){return typeof this.oldValue!==typeof this.newValue||this.oldValue instanceof Array&&!(this.newValue instanceof Array)||this.newValue instanceof Array&&!(this.oldValue instanceof Array)}static create(path,oldValue,newValue){const changes=new NodeChangeTracker(path);changes.oldValue=oldValue;changes.newValue=newValue;typeof oldValue==="object"&&Object.keys(oldValue).forEach((key=>{if(typeof newValue==="object"&&key in newValue&&newValue!==null){changes.add(key,oldValue[key],newValue[key])}else{changes.add(key,oldValue[key],null)}}));typeof newValue==="object"&&Object.keys(newValue).forEach((key=>{if(typeof oldValue!=="object"||!(key in oldValue)||oldValue[key]===null){changes.add(key,null,newValue[key])}}));return changes}}module.exports={Node:Node,NodeInfo:NodeInfo,NodeChange:NodeChange,NodeChangeTracker:NodeChangeTracker}},{"./node-info":33,"./node-value-types":35,"./storage":40}],37:[function(require,module,exports){},{}],38:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.pfs=void 0;class pfs{static get hasFileSystem(){return false}static get fs(){return null}}exports.pfs=pfs},{}],39:[function(require,module,exports){const{ID:ID,PathReference:PathReference,PathInfo:PathInfo,ascii85:ascii85,ColorStyle:ColorStyle,Utils:Utils}=require("acebase-core");const{compareValues:compareValues}=Utils;const{NodeInfo:NodeInfo}=require("./node-info");const{NodeLocker:NodeLocker}=require("./node-lock");const{VALUE_TYPES:VALUE_TYPES}=require("./node-value-types");const{Storage:Storage,StorageSettings:StorageSettings,NodeNotFoundError:NodeNotFoundError,NodeRevisionError:NodeRevisionError}=require("./storage");class ICustomStorageNodeMetaData{constructor(){this.revision="";this.revision_nr=0;this.created=0;this.modified=0;this.type=0}}class ICustomStorageNode extends ICustomStorageNodeMetaData{constructor(){super();this.value=null}}class CustomStorageTransaction{constructor(target){this.production=false;this.target={get originalPath(){return target.path},path:target.path,get write(){return target.write}};this.id=ID.generate()}async get(path){throw new Error(`CustomStorageTransaction.get must be overridden by subclass`)}async set(path,node){throw new Error(`CustomStorageTransaction.set must be overridden by subclass`)}async remove(path){throw new Error(`CustomStorageTransaction.remove must be overridden by subclass`)}async childrenOf(path,include,checkCallback,addCallback){throw new Error(`CustomStorageTransaction.childrenOf must be overridden by subclass`)}async descendantsOf(path,include,checkCallback,addCallback){throw new Error(`CustomStorageTransaction.descendantsOf must be overridden by subclass`)}async getChildCount(path){let childCount=0;await this.childrenOf(path,{metadata:false,value:false},(()=>{childCount++;return false}));return childCount}async getMultiple(paths){const map=new Map;await Promise.all(paths.map((path=>this.get(path).then((val=>map.set(path,val))))));return map}async setMultiple(nodes){await Promise.all(nodes.map((({path:path,node:node})=>this.set(path,node))))}async removeMultiple(paths){await Promise.all(paths.map((path=>this.remove(path))))}async rollback(reason){throw new Error(`CustomStorageTransaction.rollback must be overridden by subclass`)}async commit(){throw new Error(`CustomStorageTransaction.rollback must be overridden by subclass`)}async moveToParentPath(targetPath){const currentPath=this._lock&&this._lock.path||this.target.path;if(currentPath===targetPath){return targetPath}const pathInfo=CustomStorageHelpers.PathInfo.get(targetPath);if(pathInfo.isParentOf(currentPath)){if(this._lock){this._lock=await this._lock.moveToParent()}}else{throw new Error(`Locking issue. Locked path "${this._lock.path}" is not a child/descendant of "${targetPath}"`)}this.target.path=targetPath;return targetPath}}class CustomStorageSettings extends StorageSettings{constructor(settings){super(settings);settings=settings||{};if(typeof settings.ready!=="function"){throw new Error(`ready must be a function`)}if(typeof settings.getTransaction!=="function"){throw new Error(`getTransaction must be a function`)}this.name=settings.name;this.locking=settings.locking!==false;if(this.locking){this.lockTimeout=typeof settings.lockTimeout==="number"?settings.lockTimeout:120}this.ready=settings.ready;const useLocking=this.locking;const nodeLocker=useLocking?new NodeLocker(console,this.lockTimeout):null;this.getTransaction=async({path:path,write:write})=>{const transaction=await settings.getTransaction({path:path,write:write});console.assert(typeof transaction.id==="string",`transaction id not set`);const rollback=transaction.rollback;const commit=transaction.commit;transaction.commit=async()=>{const ret=await commit.call(transaction);if(useLocking){await transaction._lock.release("commit")}return ret};transaction.rollback=async reason=>{const ret=await rollback.call(transaction,reason);if(useLocking){await transaction._lock.release("rollback")}return ret};if(useLocking){transaction._lock=await nodeLocker.lock(path,transaction.id,write,`${this.name}::getTransaction`)}return transaction}}}class CustomStorageNodeAddress{constructor(containerPath){this.path=containerPath}}class CustomStorageNodeInfo extends NodeInfo{constructor(info){super(info);this.address;this.revision=info.revision;this.revision_nr=info.revision_nr;this.created=info.created;this.modified=info.modified}}class CustomStorageHelpers{static ChildPathsSql(path,columnName="path"){const where=path===""?`${columnName} <> '' AND ${columnName} NOT LIKE '%/%'`:`(${columnName} LIKE '${path}/%' OR ${columnName} LIKE '${path}[%') AND ${columnName} NOT LIKE '${path}/%/%' AND ${columnName} NOT LIKE '${path}[%]/%' AND ${columnName} NOT LIKE '${path}[%][%'`;return where}static ChildPathsRegex(path){return new RegExp(`^${path}(?:/[^/[]+|\\[[0-9]+\\])$`)}static DescendantPathsSql(path,columnName="path"){const where=path===""?`${columnName} <> ''`:`${columnName} LIKE '${path}/%' OR ${columnName} LIKE '${path}[%'`;return where}static DescendantPathsRegex(path){return new RegExp(`^${path}(?:/[^/[]+|\\[[0-9]+\\])`)}static get PathInfo(){return PathInfo}}class CustomStorage extends Storage{constructor(dbname,settings){super(dbname,settings);this._init()}async _init(){this._customImplementation=this.settings;this.debug.log(`Database "${this.name}" details:`.colorize(ColorStyle.dim));this.debug.log(`- Type: CustomStorage`.colorize(ColorStyle.dim));this.debug.log(`- Path: ${this.settings.path}`.colorize(ColorStyle.dim));this.debug.log(`- Max inline value size: ${this.settings.maxInlineValueSize}`.colorize(ColorStyle.dim));this.debug.log(`- Autoremove undefined props: ${this.settings.removeVoidProperties}`.colorize(ColorStyle.dim));await this._customImplementation.ready();const transaction=await this._customImplementation.getTransaction({path:"",write:true});const info=await this.getNodeInfo("",{transaction:transaction});if(!info.exists){await this._writeNode("",{},{transaction:transaction})}await transaction.commit();if(this.indexes.supported){await this.indexes.load()}this.emit("ready")}_storeNode(path,node,options){const getTypedChildValue=val=>{if(val===null){throw new Error(`Not allowed to store null values. remove the property`)}else if(["string","number","boolean"].includes(typeof val)){return val}else if(val instanceof Date){return{type:VALUE_TYPES.DATETIME,value:val.getTime()}}else if(val instanceof PathReference){return{type:VALUE_TYPES.REFERENCE,value:val.path}}else if(val instanceof ArrayBuffer){return{type:VALUE_TYPES.BINARY,value:ascii85.encode(val)}}else if(typeof val==="object"){console.assert(Object.keys(val).length===0,"child object stored in parent can only be empty");return val}};const unprocessed=`Caller should have pre-processed the value by converting it to a string`;if(node.type===VALUE_TYPES.ARRAY&&node.value instanceof Array){console.warn(`Unprocessed array. ${unprocessed}`);const obj={};for(let i=0;i<node.value.length;i++){obj[i]=node.value[i]}node.value=obj}if(node.type===VALUE_TYPES.BINARY&&typeof node.value!=="string"){console.warn(`Unprocessed binary value. ${unprocessed}`);node.value=ascii85.encode(node.value)}if(node.type===VALUE_TYPES.REFERENCE&&node.value instanceof PathReference){console.warn(`Unprocessed path reference. ${unprocessed}`);node.value=node.value.path}if([VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(node.type)){const original=node.value;node.value={};Object.keys(original).forEach((key=>{node.value[key]=getTypedChildValue(original[key])}))}return options.transaction.set(path,node)}_processReadNodeValue(node){const getTypedChildValue=val=>{if(val.type===VALUE_TYPES.BINARY){return ascii85.decode(val.value)}else if(val.type===VALUE_TYPES.DATETIME){return new Date(val.value)}else if(val.type===VALUE_TYPES.REFERENCE){return new PathReference(val.value)}else{throw new Error(`Unhandled child value type ${val.type}`)}};switch(node.type){case VALUE_TYPES.ARRAY:case VALUE_TYPES.OBJECT:{const obj=node.value;Object.keys(obj).forEach((key=>{let item=obj[key];if(typeof item==="object"&&"type"in item){obj[key]=getTypedChildValue(item)}}));node.value=obj;break}case VALUE_TYPES.BINARY:{node.value=ascii85.decode(node.value);break}case VALUE_TYPES.REFERENCE:{node.value=new PathReference(node.value);break}case VALUE_TYPES.STRING:{break}default:throw new Error(`Invalid standalone record value type`)}}async _readNode(path,options){let node=await options.transaction.get(path);if(node===null){return null}if(typeof node!=="object"){throw new Error(`CustomStorageTransaction.get must return an ICustomStorageNode object. Use JSON.parse if your set function stored it as a string`)}this._processReadNodeValue(node);return node}_getTypeFromStoredValue(val){let type;if(typeof val==="string"){type=VALUE_TYPES.STRING}else if(typeof val==="number"){type=VALUE_TYPES.NUMBER}else if(typeof val==="boolean"){type=VALUE_TYPES.BOOLEAN}else if(val instanceof Array){type=VALUE_TYPES.ARRAY}else if(typeof val==="object"){if("type"in val){type=val.type;val=val.value;if(type===VALUE_TYPES.DATETIME){val=new Date(val)}else if(type===VALUE_TYPES.REFERENCE){val=new PathReference(val)}}else{type=VALUE_TYPES.OBJECT}}else{throw new Error(`Unknown value type`)}return{type:type,value:val}}async _writeNode(path,value,options){if(!options.merge&&this.valueFitsInline(value)&&path!==""){throw new Error(`invalid value to store in its own node`)}else if(path===""&&(typeof value!=="object"||value instanceof Array)){throw new Error(`Invalid root node value. Must be an object`)}if(typeof options.diff==="undefined"&&typeof options.currentValue!=="undefined"){const diff=compareValues(options.currentValue,value);if(options.merge&&typeof diff==="object"){diff.removed=diff.removed.filter((key=>value[key]===null))}options.diff=diff}if(options.diff==="identical"){return}const transaction=options.transaction;const currentRow=options.currentValue===null?null:await this._readNode(path,{transaction:transaction});if(options.merge&¤tRow){if(currentRow.type===VALUE_TYPES.ARRAY&&!(value instanceof Array)&&typeof value==="object"&&Object.keys(value).some((key=>isNaN(key)))){throw new Error(`Cannot merge existing array of path "${path}" with an object`)}if(value instanceof Array&¤tRow.type!==VALUE_TYPES.ARRAY){throw new Error(`Cannot merge existing object of path "${path}" with an array`)}}const revision=options.revision||ID.generate();let mainNode={type:currentRow&¤tRow.type===VALUE_TYPES.ARRAY?VALUE_TYPES.ARRAY:VALUE_TYPES.OBJECT,value:{}};const childNodeValues={};if(value instanceof Array){mainNode.type=VALUE_TYPES.ARRAY;const obj={};for(let i=0;i<value.length;i++){obj[i]=value[i]}value=obj}else if(value instanceof PathReference){mainNode.type=VALUE_TYPES.REFERENCE;mainNode.value=value.path}else if(value instanceof ArrayBuffer){mainNode.type=VALUE_TYPES.BINARY;mainNode.value=ascii85.encode(value)}else if(typeof value==="string"){mainNode.type=VALUE_TYPES.STRING;mainNode.value=value}const currentIsObjectOrArray=currentRow?[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(currentRow.type):false;const newIsObjectOrArray=[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(mainNode.type);const children={current:[],new:[]};let currentObject=null;if(currentIsObjectOrArray){currentObject=currentRow.value;children.current=Object.keys(currentObject);if(newIsObjectOrArray){mainNode.value=currentObject}}if(newIsObjectOrArray){if(!options.merge){Object.keys(mainNode.value).forEach((key=>{if(!(key in value)){value[key]=null}}))}Object.keys(value).forEach((key=>{const val=value[key];delete mainNode.value[key];if(val===null){return}else if(typeof val==="undefined"){if(this.settings.removeVoidProperties===true){delete value[key];return}else{throw new Error(`Property "${key}" has invalid value. Cannot store undefined values. Set removeVoidProperties option to true to automatically remove undefined properties`)}}if(this.valueFitsInline(val)){mainNode.value[key]=val}else{childNodeValues[key]=val}}))}const isArray=mainNode.type===VALUE_TYPES.ARRAY;if(currentRow){this.debug.log(`Node "/${path}" is being ${options.merge?"updated":"overwritten"}`.colorize(ColorStyle.cyan));if(currentIsObjectOrArray||newIsObjectOrArray){const pathInfo=PathInfo.get(path);const keys=[];let checkExecuted=false;const includeChildCheck=childPath=>{checkExecuted=true;if(!transaction.production&&!pathInfo.isParentOf(childPath)){throw new Error(`"${childPath}" is not a child of "${path}" - childrenOf must only check and return paths that are children`)}return true};const addChildPath=childPath=>{if(!checkExecuted){throw new Error(`${this._customImplementation.info} childrenOf did not call checkCallback before addCallback`)}const key=PathInfo.get(childPath).key;keys.push(key.toString());return true};await transaction.childrenOf(path,{metadata:false,value:false},includeChildCheck,addChildPath);children.current=children.current.concat(keys);if(newIsObjectOrArray){if(options&&options.merge){children.new=children.current.slice()}Object.keys(value).forEach((key=>{if(!children.new.includes(key)){children.new.push(key)}}))}const changes={insert:children.new.filter((key=>!children.current.includes(key))),update:[],delete:options&&options.merge?Object.keys(value).filter((key=>value[key]===null)):children.current.filter((key=>!children.new.includes(key)))};changes.update=children.new.filter((key=>children.current.includes(key)&&!changes.delete.includes(key)));if(isArray&&options.merge&&(changes.insert.length>0||changes.delete.length>0)){const newArrayKeys=changes.update.concat(changes.insert);const isExhaustive=newArrayKeys.every(((k,index,arr)=>arr.includes(index.toString())));if(!isExhaustive){throw new Error(`Elements cannot be inserted beyond, or removed before the end of an array. Rewrite the whole array at path "${path}" or change your schema to use an object collection instead`)}}const writePromises=Object.keys(childNodeValues).map((key=>{if(isArray){key=parseInt(key)}const childDiff=typeof options.diff==="object"?options.diff.forChild(key):undefined;if(childDiff==="identical"){return}const childPath=pathInfo.childPath(key);const childValue=childNodeValues[key];const currentChildValue=typeof options.currentValue==="undefined"?undefined:options.currentValue!==null&&typeof options.currentValue==="object"&&key in options.currentValue?options.currentValue[key]:null;return this._writeNode(childPath,childValue,{transaction:transaction,revision:revision,merge:false,currentValue:currentChildValue,diff:childDiff})}));const movingNodes=keys.filter((key=>key in mainNode.value));const deleteDedicatedKeys=changes.delete.concat(movingNodes);const deletePromises=deleteDedicatedKeys.map((key=>{if(isArray){key=parseInt(key)}const childPath=pathInfo.childPath(key);return this._deleteNode(childPath,{transaction:transaction})}));const promises=writePromises.concat(deletePromises);await Promise.all(promises)}const p=this._storeNode(path,{type:mainNode.type,value:mainNode.value,revision:currentRow.revision,revision_nr:currentRow.revision_nr+1,created:currentRow.created,modified:Date.now()},{transaction:transaction});if(p instanceof Promise){return await p}}else{this.debug.log(`Node "/${path}" is being created`.colorize(ColorStyle.cyan));if(isArray){const arrayKeys=Object.keys(mainNode.value).concat(Object.keys(childNodeValues));const isExhaustive=arrayKeys.every(((k,index,arr)=>arr.includes(index.toString())));if(!isExhaustive){throw new Error(`Cannot store arrays with missing entries`)}}const promises=Object.keys(childNodeValues).map((key=>{if(isArray){key=parseInt(key)}const childPath=PathInfo.getChildPath(path,key);const childValue=childNodeValues[key];return this._writeNode(childPath,childValue,{transaction:transaction,revision:revision,merge:false,currentValue:null})}));const p=this._storeNode(path,{type:mainNode.type,value:mainNode.value,revision:revision,revision_nr:1,created:Date.now(),modified:Date.now()},{transaction:transaction});promises.push(p);return Promise.all(promises)}}async _deleteNode(path,options){const pathInfo=PathInfo.get(path);this.debug.log(`Node "/${path}" is being deleted`.colorize(ColorStyle.cyan));const deletePaths=[path];let checkExecuted=false;const includeDescendantCheck=descPath=>{checkExecuted=true;if(!transaction.production&&!pathInfo.isAncestorOf(descPath)){throw new Error(`"${descPath}" is not a descendant of "${path}" - descendantsOf must only check and return paths that are descendants`)}return true};const addDescendant=descPath=>{if(!checkExecuted){throw new Error(`${this._customImplementation.info} descendantsOf did not call checkCallback before addCallback`)}deletePaths.push(descPath);return true};const transaction=options.transaction;await transaction.descendantsOf(path,{metadata:false,value:false},includeDescendantCheck,addDescendant);this.debug.log(`Nodes ${deletePaths.map((p=>`"/${p}"`)).join(",")} are being deleted`.colorize(ColorStyle.cyan));return transaction.removeMultiple(deletePaths)}getChildren(path,options){options=options||{};var callback;const generator={next(valueCallback){callback=valueCallback;return start()}};const start=async()=>{const transaction=options.transaction||await this._customImplementation.getTransaction({path:path,write:false});try{let canceled=false;await(async()=>{let node=await this._readNode(path,{transaction:transaction});if(!node){throw new NodeNotFoundError(`Node "/${path}" does not exist`)}if(![VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(node.type)){return}const isArray=node.type===VALUE_TYPES.ARRAY;const value=node.value;let keys=Object.keys(value);if(options.keyFilter){keys=keys.filter((key=>options.keyFilter.includes(key)))}const pathInfo=PathInfo.get(path);keys.length>0&&keys.every((key=>{let child=this._getTypeFromStoredValue(value[key]);const info=new CustomStorageNodeInfo({path:pathInfo.childPath(key),key:isArray?null:key,index:isArray?key:null,type:child.type,address:null,exists:true,value:child.value,revision:node.revision,revision_nr:node.revision_nr,created:node.created,modified:node.modified});canceled=callback(info)===false;return!canceled}));if(canceled){return}let checkExecuted=false;const includeChildCheck=childPath=>{checkExecuted=true;if(!transaction.production&&!pathInfo.isParentOf(childPath)){throw new Error(`"${childPath}" is not a child of "${path}" - childrenOf must only check and return paths that are children`)}if(options.keyFilter){const key=PathInfo.get(childPath).key;return options.keyFilter.includes(key)}return true};const addChildNode=(childPath,node)=>{if(!checkExecuted){throw new Error(`${this._customImplementation.info} childrenOf did not call checkCallback before addCallback`)}const key=PathInfo.get(childPath).key;const info=new CustomStorageNodeInfo({path:childPath,type:node.type,key:isArray?null:key,index:isArray?key:null,address:new CustomStorageNodeAddress(childPath),exists:true,value:null,revision:node.revision,revision_nr:node.revision_nr,created:new Date(node.created),modified:new Date(node.modified)});canceled=callback(info)===false;return!canceled};await transaction.childrenOf(path,{metadata:true,value:false},includeChildCheck,addChildNode)})();if(!options.transaction){await transaction.commit()}return canceled}catch(err){if(!options.transaction){await transaction.rollback(err)}throw err}};return generator}async getNode(path,options){options=options||{};const transaction=options.transaction||await this._customImplementation.getTransaction({path:path,write:false});try{const node=await(async()=>{const filtered=options.include&&options.include.length>0||options.exclude&&options.exclude.length>0||options.child_objects===false;const pathInfo=PathInfo.get(path);const targetNode=await this._readNode(path,{transaction:transaction});if(!targetNode){if(path===""){return{value:null}}const lockPath=await transaction.moveToParentPath(pathInfo.parentPath);console.assert(lockPath===pathInfo.parentPath,`transaction.moveToParentPath() did not move to the right parent path of "${path}"`);let parentNode=await this._readNode(pathInfo.parentPath,{transaction:transaction});if(parentNode&&[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(parentNode.type)&&pathInfo.key in parentNode.value){const childValueInfo=this._getTypeFromStoredValue(parentNode.value[pathInfo.key]);return{revision:parentNode.revision,revision_nr:parentNode.revision_nr,created:parentNode.created,modified:parentNode.modified,type:childValueInfo.type,value:childValueInfo.value}}return{value:null}}let checkExecuted=false;const includeDescendantCheck=(descPath,metadata)=>{checkExecuted=true;if(!transaction.production&&!pathInfo.isAncestorOf(descPath)){throw new Error(`"${descPath}" is not a descendant of "${path}" - descendantsOf must only check and return paths that are descendants`)}if(!filtered){return true}let checkPath=descPath.slice(path.length);if(checkPath[0]==="/"){checkPath=checkPath.slice(1)}const checkPathInfo=new PathInfo(checkPath);let include=(options.include&&options.include.length>0?options.include.some((k=>checkPathInfo.equals(k)||checkPathInfo.isDescendantOf(k))):true)&&(options.exclude&&options.exclude.length>0?!options.exclude.some((k=>checkPathInfo.equals(k)||checkPathInfo.isDescendantOf(k))):true);if(include&&options.child_objects===false&&(pathInfo.isParentOf(descPath)&&[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(metadata?metadata.type:-1)||PathInfo.getPathKeys(descPath).length>pathInfo.pathKeys.length+1)){include=false}return include};const descRows=[];const addDescendant=(descPath,node)=>{if(!checkExecuted){throw new Error(`${this._customImplementation.info} descendantsOf did not call checkCallback before addCallback`)}if(options.child_objects===false&&[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(node.type)){return true}this._processReadNodeValue(node);node.path=descPath;descRows.push(node);return true};await transaction.descendantsOf(path,{metadata:true,value:true},includeDescendantCheck,addDescendant);this.debug.log(`Read node "/${path}" and ${filtered?"(filtered) ":""}descendants from ${descRows.length+1} records`.colorize(ColorStyle.magenta));const result=targetNode;const objectToArray=obj=>{const arr=[];Object.keys(obj).forEach((key=>{let index=parseInt(key);arr[index]=obj[index]}));return arr};if(targetNode.type===VALUE_TYPES.ARRAY){result.value=objectToArray(result.value)}if(targetNode.type===VALUE_TYPES.OBJECT||targetNode.type===VALUE_TYPES.ARRAY){const targetPathKeys=PathInfo.getPathKeys(path);let value=targetNode.value;for(let i=0;i<descRows.length;i++){const otherNode=descRows[i];const pathKeys=PathInfo.getPathKeys(otherNode.path);const trailKeys=pathKeys.slice(targetPathKeys.length);let parent=value;for(let j=0;j<trailKeys.length;j++){console.assert(typeof parent==="object","parent must be an object/array to have children!!");const key=trailKeys[j];const isLast=j===trailKeys.length-1;const nodeType=isLast?otherNode.type:typeof trailKeys[j+1]==="number"?VALUE_TYPES.ARRAY:VALUE_TYPES.OBJECT;let nodeValue;if(!isLast){nodeValue=nodeType===VALUE_TYPES.OBJECT?{}:[]}else{nodeValue=otherNode.value;if(nodeType===VALUE_TYPES.ARRAY){nodeValue=objectToArray(nodeValue)}}if(key in parent){const mergePossible=typeof parent[key]===typeof nodeValue&&[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(nodeType);if(!mergePossible){this.debug.error(`The value stored in node "${otherNode.path}" cannot be merged with the parent node, value will be ignored. This error should disappear once the target node value is updated. See issue #20 for more information`)}else{Object.keys(nodeValue).forEach((childKey=>{console.assert(!(childKey in parent[key]),"child key is in parent value already?! HOW?!");parent[key][childKey]=nodeValue[childKey]}))}}else{parent[key]=nodeValue}parent=parent[key]}}}else if(descRows.length>0){throw new Error(`multiple records found for non-object value!`)}if(options.child_objects===false){Object.keys(result.value).forEach((key=>{if(typeof result.value[key]==="object"&&result.value[key].constructor===Object){console.assert(Object.keys(result.value[key]).length===0);delete result.value[key]}}))}if(options.include){}if(options.exclude){const process=(obj,keys)=>{if(typeof obj!=="object"){return}const key=keys[0];if(key==="*"){Object.keys(obj).forEach((k=>{process(obj[k],keys.slice(1))}))}else if(keys.length>1){key in obj&&process(obj[key],keys.slice(1))}else{delete obj[key]}};options.exclude.forEach((path=>{const checkKeys=PathInfo.getPathKeys(path);process(result.value,checkKeys)}))}return result})();if(!options.transaction){await transaction.commit()}return node}catch(err){if(!options.transaction){await transaction.rollback(err)}throw err}}async getNodeInfo(path,options){options=options||{};const pathInfo=PathInfo.get(path);const transaction=options.transaction||await this._customImplementation.getTransaction({path:path,write:false});try{const node=await this._readNode(path,{transaction:transaction});const info=new CustomStorageNodeInfo({path:path,key:typeof pathInfo.key==="string"?pathInfo.key:null,index:typeof pathInfo.key==="number"?pathInfo.key:null,type:node?node.type:0,exists:node!==null,address:node?new CustomStorageNodeAddress(path):null,created:node?new Date(node.created):null,modified:node?new Date(node.modified):null,revision:node?node.revision:null,revision_nr:node?node.revision_nr:null});if(!node&&path!==""){const lockPath=await transaction.moveToParentPath(pathInfo.parentPath);console.assert(lockPath===pathInfo.parentPath,`transaction.moveToParentPath() did not move to the right parent path of "${path}"`);const parent=await this._readNode(pathInfo.parentPath,{transaction:transaction});if(parent&&[VALUE_TYPES.OBJECT,VALUE_TYPES.ARRAY].includes(parent.type)&&pathInfo.key in parent.value){info.exists=true;info.value=parent.value[pathInfo.key];info.address=null;info.type=parent.type;info.created=new Date(parent.created);info.modified=new Date(parent.modified);info.revision=parent.revision;info.revision_nr=parent.revision_nr}else{info.address=null}}if(options.include_child_count){info.childCount=0;if([VALUE_TYPES.ARRAY,VALUE_TYPES.OBJECT].includes(info.valueType)&&info.address){info.childCount=node.value?Object.keys(node.value).length:0;info.childCount+=await transaction.getChildCount(path)}}if(!options.transaction){await transaction.commit()}return info}catch(err){if(!options.transaction){await transaction.rollback(err)}throw err}}async setNode(path,value,options={suppress_events:false,context:null}){const pathInfo=PathInfo.get(path);const transaction=options.transaction||await this._customImplementation.getTransaction({path:path,write:true});try{if(path===""){if(value===null||typeof value!=="object"||value instanceof Array||value instanceof ArrayBuffer||"buffer"in value&&value.buffer instanceof ArrayBuffer){throw new Error(`Invalid value for root node: ${value}`)}await this._writeNodeWithTracking("",value,{merge:false,transaction:transaction,suppress_events:options.suppress_events,context:options.context})}else if(typeof options.assert_revision!=="undefined"){const info=await this.getNodeInfo(path,{transaction:transaction});if(info.revision!==options.assert_revision){throw new NodeRevisionError(`revision '${info.revision}' does not match requested revision '${options.assert_revision}'`)}if(info.address&&info.address.path===path&&value!==null&&!this.valueFitsInline(value)){await this._writeNodeWithTracking(path,value,{merge:false,transaction:transaction,suppress_events:options.suppress_events,context:options.context})}else{const lockPath=await transaction.moveToParentPath(pathInfo.parentPath);console.assert(lockPath===pathInfo.parentPath,`transaction.moveToParentPath() did not move to the right parent path of "${path}"`);await this._writeNodeWithTracking(pathInfo.parentPath,{[pathInfo.key]:value},{merge:true,transaction:transaction,suppress_events:options.suppress_events,context:options.context})}}else{const lockPath=await transaction.moveToParentPath(pathInfo.parentPath);console.assert(lockPath===pathInfo.parentPath,`transaction.moveToParentPath() did not move to the right parent path of "${path}"`);await this.updateNode(pathInfo.parentPath,{[pathInfo.key]:value},{transaction:transaction,suppress_events:options.suppress_events,context:options.context})}if(!options.transaction){await transaction.commit()}}catch(err){if(!options.transaction){await transaction.rollback(err)}throw err}}async updateNode(path,updates,options={suppress_events:false,context:null}){if(typeof updates!=="object"){throw new Error(`invalid updates argument`)}else if(Object.keys(updates).length===0){return}const transaction=options.transaction||await this._customImplementation.getTransaction({path:path,write:true});try{const nodeInfo=await this.getNodeInfo(path,{transaction:transaction});const pathInfo=PathInfo.get(path);if(nodeInfo.exists&&nodeInfo.address&&nodeInfo.address.path===path){await this._writeNodeWithTracking(path,updates,{transaction:transaction,merge:true,suppress_events:options.suppress_events,context:options.context})}else if(nodeInfo.exists){const pathInfo=PathInfo.get(path);const lockPath=await transaction.moveToParentPath(pathInfo.parentPath);console.assert(lockPath===pathInfo.parentPath,`transaction.moveToParentPath() did not move to the right parent path of "${path}"`);await this._writeNodeWithTracking(pathInfo.parentPath,{[pathInfo.key]:updates},{transaction:transaction,merge:true,suppress_events:options.suppress_events,context:options.context})}else{const lockPath=await transaction.moveToParentPath(pathInfo.parentPath);console.assert(lockPath===pathInfo.parentPath,`transaction.moveToParentPath() did not move to the right parent path of "${path}"`);await this.updateNode(pathInfo.parentPath,{[pathInfo.key]:updates},{transaction:transaction,suppress_events:options.suppress_events,context:options.context})}if(!options.transaction){await transaction.commit()}}catch(err){if(!options.transaction){await transaction.rollback(err)}throw err}}}module.exports={CustomStorageNodeAddress:CustomStorageNodeAddress,CustomStorageNodeInfo:CustomStorageNodeInfo,CustomStorage:CustomStorage,CustomStorageSettings:CustomStorageSettings,CustomStorageHelpers:CustomStorageHelpers,CustomStorageTransaction:CustomStorageTransaction,ICustomStorageNodeMetaData:ICustomStorageNodeMetaData,ICustomStorageNode:ICustomStorageNode}},{"./node-info":33,"./node-lock":34,"./node-value-types":35,"./storage":40,"acebase-core":12}],40:[function(require,module,exports){const{Utils:Utils,DebugLogger:DebugLogger,PathInfo:PathInfo,ID:ID,PathReference:PathReference,ascii85:ascii85,SimpleEventEmitter:SimpleEventEmitter,ColorStyle:ColorStyle,SchemaDefinition:SchemaDefinition}=require("acebase-core");const{VALUE_TYPES:VALUE_TYPES}=require("./node-value-types");const{NodeInfo:NodeInfo}=require("./node-info");const{compareValues:compareValues,getChildValues:getChildValues,encodeString:encodeString,defer:defer}=Utils;const{IPCPeer:IPCPeer,RemoteIPCPeer:RemoteIPCPeer}=require("./ipc");const{pfs:pfs}=require("./promise-fs");const DEBUG_MODE=false;class NodeNotFoundError extends Error{}class NodeRevisionError extends Error{}class SchemaValidationError extends Error{constructor(reason){super(`Schema validation failed: ${reason}`);this.reason=reason}}class IWriteNodeResult{}class StorageSettings{constructor(settings){settings=settings||{};this.maxInlineValueSize=typeof settings.maxInlineValueSize==="number"?settings.maxInlineValueSize:50;this.removeVoidProperties=settings.removeVoidProperties===true;this.path=settings.path||".";if(this.path.endsWith("/")){this.path=this.path.slice(0,-1)}this.logLevel=settings.logLevel||"log";this.info=settings.info||"realtime database";this.type=settings.type||"data";this.ipc=settings.ipc;this.lockTimeout=typeof settings.lockTimeout==="number"?settings.lockTimeout:120}}class Storage extends SimpleEventEmitter{createTid(){return DEBUG_MODE?++this._lastTid:ID.generate()}constructor(name,settings){super();this.name=name;this.settings=settings;this.debug=new DebugLogger(settings.logLevel,`[${name}${typeof settings.type==="string"&&settings.type!=="data"?`:${settings.type}`:""}]`);const ipcName=name+(typeof settings.type==="string"?`_${settings.type}`:"");if(settings.ipc){if(typeof settings.ipc.port!=="number"){throw new Error(`IPC port number must be a number`)}if(!["master","worker"].includes(settings.ipc.role)){throw new Error(`IPC client role must be either "master" or "worker", not "${settings.ipc.role}"`)}const ipcSettings=Object.assign({dbname:ipcName},settings.ipc);this.ipc=new RemoteIPCPeer(this,ipcSettings)}else{this.ipc=new IPCPeer(this,ipcName)}this.ipc.once("exit",(code=>{if(this.indexes.supported){this.indexes.close()}}));this.nodeLocker={lock:(path,tid,write,comment)=>this.ipc.lock({path:path,tid:tid,write:write,comment:comment})};this._lastTid=0;const{DataIndex:DataIndex,ArrayIndex:ArrayIndex,FullTextIndex:FullTextIndex,GeoIndex:GeoIndex}=require("./data-index");this._schemas=[];const _indexes=[];const storage=this;this.indexes={get supported(){return pfs&&pfs.hasFileSystem},async create(path,key,options={rebuild:false,type:undefined,include:undefined}){if(!this.supported){throw new Error(`Indexes are not supported in current environment because it requires Node.js fs`)}path=path.replace(/\/\*$/,"");const rebuild=options&&options.rebuild===true;const indexType=options&&options.type||"normal";let includeKeys=options&&options.include||[];if(typeof includeKeys==="string"){includeKeys=[includeKeys]}const existingIndex=_indexes.find((index=>index.path===path&&index.key===key&&index.type===indexType&&index.includeKeys.length===includeKeys.length&&index.includeKeys.every(((key,index)=>includeKeys[index]===key))));if(existingIndex&&rebuild!==true){storage.debug.log(`Index on "/${path}/*/${key}" already exists`.colorize(ColorStyle.inverse));return existingIndex}if(!storage.ipc.isMaster){const result=await storage.ipc.sendRequest({type:"index.create",path:path,key:key,options:options});if(result.ok){return this.add(result.fileName)}throw new Error(result.reason)}await pfs.mkdir(`${storage.settings.path}/${storage.name}.acebase`).catch((err=>{if(err.code!=="EEXIST"){throw err}}));const index=existingIndex||(()=>{switch(indexType){case"array":return new ArrayIndex(storage,path,key,{include:options.include,config:options.config});case"fulltext":return new FullTextIndex(storage,path,key,{include:options.include,config:options.config});case"geo":return new GeoIndex(storage,path,key,{include:options.include,config:options.config});default:return new DataIndex(storage,path,key,{include:options.include,config:options.config})}})();if(!existingIndex){_indexes.push(index)}await index.build().catch((err=>{storage.debug.error(`Index build on "/${path}/*/${key}" failed: ${err.message} (code: ${err.code})`.colorize(ColorStyle.red));if(!existingIndex){_indexes.splice(_indexes.indexOf(index),1)}throw err}));storage.ipc.sendNotification({type:"index.created",fileName:index.fileName,path:path,key:key,options:options});return index},get(path,key=null){const matchesNamedWildcardPath=index=>{if(!index.path.includes("$")){return false}const pattern="^"+index.path.replace(/\$[a-z0-9_]+/gi,"[a-z0-9_]+|\\*")+"$";const re=new RegExp(pattern,"i");return re.test(path)};return _indexes.filter((index=>(index.path===path||matchesNamedWildcardPath(index))&&(key===null||key===index.key)))},getAll(targetPath,options={parentPaths:true,childPaths:true}){const pathKeys=PathInfo.getPathKeys(targetPath);return _indexes.filter((index=>{const indexKeys=PathInfo.getPathKeys(index.path+"/*");if(options.parentPaths&&indexKeys.every(((key,i)=>key==="*"||pathKeys[i]===key))&&[index.key].concat(...index.includeKeys).includes(pathKeys[indexKeys.length])){return true}else if(indexKeys.length<pathKeys.length){return false}else if(!options.childPaths&&indexKeys.length!==pathKeys.length){return false}return pathKeys.every(((key,i)=>[key,"*"].includes(indexKeys[i])))}))},list(){return _indexes.slice()},async load(){_indexes.splice(0);if(!pfs.hasFileSystem){return}let files=[];try{files=await pfs.readdir(`${storage.settings.path}/${storage.name}.acebase`)}catch(err){if(err.code!=="ENOENT"){storage.debug.error(err)}}const promises=[];files.forEach((fileName=>{if(!fileName.endsWith(".idx")){return}const needsStoragePrefix=settings.type!=="data";const hasStoragePrefix=/^\[[a-z]+\]-/.test(fileName);if(!needsStoragePrefix&&!hasStoragePrefix||needsStoragePrefix&&fileName.startsWith(`[${settings.type}]-`)){const p=this.add(fileName);promises.push(p)}}));await Promise.all(promises)},async add(fileName){try{const index=await DataIndex.readFromFile(storage,fileName);_indexes.push(index)}catch(err){storage.debug.error(err)}},async delete(index){await index.delete();storage.ipc.sendNotification({type:"index.deleted",fileName:index.fileName,path:index.path,keys:index.key})},async remove(fileName){const index=_indexes.find((index=>index.fileName===fileName));if(!index){throw new Error(`Index ${fileName} not found`)}_indexes.splice(_indexes.indexOf(index),1)},async close(){const promises=this.list().map((index=>index.close().catch((err=>storage.debug.error(err)))));await Promise.all(promises)}};const _subs={};const _supportedEvents=["value","child_added","child_changed","child_removed","mutated","mutations"];_supportedEvents.push(..._supportedEvents.map((event=>`notify_${event}`)));this.subscriptions={add:(path,type,callback)=>{if(_supportedEvents.indexOf(type)<0){throw new TypeError(`Invalid event type "${type}"`)}let pathSubs=_subs[path];if(!pathSubs){pathSubs=_subs[path]=[]}pathSubs.push({created:Date.now(),type:type,callback:callback});this.emit("subscribe",{path:path,event:type,callback:callback})},remove:(path,type=undefined,callback=undefined)=>{let pathSubs=_subs[path];if(!pathSubs){return}let i,next=()=>pathSubs.findIndex((ps=>(type?ps.type===type:true)&&(callback?ps.callback===callback:true)));while((i=next())>=0){pathSubs.splice(i,1)}this.emit("unsubscribe",{path:path,event:type,callback:callback})},hasValueSubscribersForPath(path){const valueNeeded=this.getValueSubscribersForPath(path);return!!valueNeeded},getValueSubscribersForPath(path){const pathInfo=new PathInfo(path);const valueSubscribers=[];Object.keys(_subs).forEach((subscriptionPath=>{if(pathInfo.equals(subscriptionPath)||pathInfo.isDescendantOf(subscriptionPath)){let pathSubs=_subs[subscriptionPath];const eventPath=PathInfo.fillVariables(subscriptionPath,path);pathSubs.filter((sub=>!sub.type.startsWith("notify_"))).forEach((sub=>{let dataPath=null;if(sub.type==="value"){dataPath=eventPath}else if(["mutated","mutations"].includes(sub.type)&&pathInfo.isDescendantOf(eventPath)){dataPath=path}else if(sub.type==="child_changed"&&path!==eventPath){let childKey=PathInfo.getPathKeys(path.slice(eventPath.length).replace(/^\//,""))[0];dataPath=PathInfo.getChildPath(eventPath,childKey)}else if(["child_added","child_removed"].includes(sub.type)&&pathInfo.isChildOf(eventPath)){let childKey=PathInfo.getPathKeys(path.slice(eventPath.length).replace(/^\//,""))[0];dataPath=PathInfo.getChildPath(eventPath,childKey)}if(dataPath!==null&&!valueSubscribers.includes((s=>s.type===sub.type&&s.eventPath===eventPath))){valueSubscribers.push({type:sub.type,eventPath:eventPath,dataPath:dataPath,subscriptionPath:subscriptionPath})}}))}}));return valueSubscribers},getAllSubscribersForPath(path){const pathInfo=PathInfo.get(path);const subscribers=[];Object.keys(_subs).forEach((subscriptionPath=>{if(pathInfo.isOnTrailOf(subscriptionPath)){let pathSubs=_subs[subscriptionPath];const eventPath=PathInfo.fillVariables(subscriptionPath,path);pathSubs.forEach((sub=>{let dataPath=null;if(sub.type==="value"||sub.type==="notify_value"){dataPath=eventPath}else if(["child_changed","notify_child_changed"].includes(sub.type)){let childKey=path===eventPath||pathInfo.isAncestorOf(eventPath)?"*":PathInfo.getPathKeys(path.slice(eventPath.length).replace(/^\//,""))[0];dataPath=PathInfo.getChildPath(eventPath,childKey)}else if(["mutated","mutations","notify_mutated","notify_mutations"].includes(sub.type)){dataPath=path}else if(["child_added","child_removed","notify_child_added","notify_child_removed"].includes(sub.type)&&(pathInfo.isChildOf(eventPath)||path===eventPath||pathInfo.isAncestorOf(eventPath))){let childKey=path===eventPath||pathInfo.isAncestorOf(eventPath)?"*":PathInfo.getPathKeys(path.slice(eventPath.length).replace(/^\//,""))[0];dataPath=PathInfo.getChildPath(eventPath,childKey)}if(dataPath!==null&&!subscribers.some((s=>s.type===sub.type&&s.eventPath===eventPath&&s.subscriptionPath===subscriptionPath))){subscribers.push({type:sub.type,eventPath:eventPath,dataPath:dataPath,subscriptionPath:subscriptionPath})}}))}}));return subscribers},trigger(event,path,dataPath,oldValue,newValue,context){const pathSubscriptions=_subs[path]||[];pathSubscriptions.filter((sub=>sub.type===event)).forEach((sub=>{sub.callback(null,dataPath,newValue,oldValue,context)}))}}}async close(){await this.ipc.exit()}get path(){return`${this.settings.path}/${this.name}.acebase`}valueFitsInline(value){if(typeof value==="number"||typeof value==="boolean"||value instanceof Date){return true}else if(typeof value==="string"){if(value.length>this.settings.maxInlineValueSize){return false}const encoded=encodeString(value);return encoded.length<this.settings.maxInlineValueSize}else if(value instanceof PathReference){if(value.path.length>this.settings.maxInlineValueSize){return false}const encoded=encodeString(value.path);return encoded.length<this.settings.maxInlineValueSize}else if(value instanceof ArrayBuffer){return value.length<this.settings.maxInlineValueSize}else if(value instanceof Array){return value.length===0}else if(typeof value==="object"){return Object.keys(value).length===0}else{throw new TypeError(`What else is there?`)}}_writeNode(path,value,options){throw new Error(`This method must be implemented by subclass`)}getUpdateImpact(path,suppressEvents){let topEventPath=path;let hasValueSubscribers=false;let eventSubscriptions=suppressEvents?[]:this.subscriptions.getAllSubscribersForPath(path);const valueSubscribers=suppressEvents?[]:this.subscriptions.getValueSubscribersForPath(path);if(valueSubscribers.length>0){hasValueSubscribers=true;let eventPaths=valueSubscribers.map((sub=>({path:sub.dataPath,keys:PathInfo.getPathKeys(sub.dataPath)}))).sort(((a,b)=>{if(a.keys.length<b.keys.length)return-1;else if(a.keys.length>b.keys.length)return 1;return 0}));let first=eventPaths[0];topEventPath=first.path;if(valueSubscribers.filter((sub=>sub.dataPath===topEventPath)).every((sub=>sub.type==="mutated"||sub.type.startsWith("notify_")))){hasValueSubscribers=false}topEventPath=PathInfo.fillVariables(topEventPath,path)}const indexes=this.indexes.getAll(path,{childPaths:true,parentPaths:true}).map((index=>({index:index,keys:PathInfo.getPathKeys(index.path)}))).sort(((a,b)=>{if(a.keys.length<b.keys.length){return-1}else if(a.keys.length>b.keys.length){return 1}return 0})).map((obj=>obj.index));let keysFilter=[];if(indexes.length>0){indexes.sort(((a,b)=>{if(typeof a._pathKeys==="undefined"){a._pathKeys=PathInfo.getPathKeys(a.path)}if(typeof b._pathKeys==="undefined"){b._pathKeys=PathInfo.getPathKeys(b.path)}if(a._pathKeys.length<b._pathKeys.length)return-1;else if(a._pathKeys.length>b._pathKeys.length)return 1;return 0}));const topIndex=indexes[0];let topIndexPath=topIndex.path===path?path:PathInfo.fillVariables(`${topIndex.path}/*`,path);if(topIndexPath.length<topEventPath.length){topEventPath=topIndexPath;indexes.filter((index=>index.path===topIndex.path)).forEach((index=>{let keys=[index.key].concat(index.includeKeys);keys.forEach((key=>!keysFilter.includes(key)&&keysFilter.push(key)))}))}}return{topEventPath:topEventPath,eventSubscriptions:eventSubscriptions,valueSubscribers:valueSubscribers,hasValueSubscribers:hasValueSubscribers,indexes:indexes,keysFilter:keysFilter}}async _writeNodeWithTracking(path,value,options={merge:false,transaction:undefined,tid:undefined,_customWriteFunction:undefined,waitForIndexUpdates:true,suppress_events:false,context:null,impact:null}){options=options||{};if(!options.tid&&!options.transaction){throw new Error(`_writeNodeWithTracking MUST be executed with a tid OR transaction!`)}options.merge=options.merge===true;const validation=this.validateSchema(path,value,{updates:options.merge});if(!validation.ok){throw new SchemaValidationError(validation.reason)}const tid=options.tid;const transaction=options.transaction;let topEventData=null;let{topEventPath:topEventPath,eventSubscriptions:eventSubscriptions,hasValueSubscribers:hasValueSubscribers,indexes:indexes,keysFilter:keysFilter}=options.impact?options.impact:this.getUpdateImpact(path,options.suppress_events);const writeNode=()=>{if(typeof options._customWriteFunction==="function"){return options._customWriteFunction()}if(topEventData){const pathKeys=PathInfo.getPathKeys(path);const eventPathKeys=PathInfo.getPathKeys(topEventPath);const trailKeys=pathKeys.slice(eventPathKeys.length);let currentValue=topEventData;while(trailKeys.length>0&¤tValue!==null){const childKey=trailKeys.shift();currentValue=typeof currentValue==="object"&&childKey in currentValue?currentValue[childKey]:null}options.currentValue=currentValue}return this._writeNode(path,value,options)};const transactionLoggingEnabled=this.settings.transactions&&this.settings.transactions.log===true;if(eventSubscriptions.length===0&&indexes.length===0&&!transactionLoggingEnabled){return writeNode()}if(!hasValueSubscribers&&options.merge===true&&keysFilter.length===0){keysFilter=Object.keys(value);if(topEventPath!==path){let trailPath=path.slice(topEventPath.length);keysFilter=keysFilter.map((key=>`${trailPath}/${key}`))}}const eventNodeInfo=await this.getNodeInfo(topEventPath,{transaction:transaction,tid:tid});let currentValue=null;if(eventNodeInfo.exists){let valueOptions={transaction:transaction,tid:tid};if(keysFilter.length>0){valueOptions.include=keysFilter}if(topEventPath===""&&typeof valueOptions.include==="undefined"){this.debug.warn(`WARNING: One or more value event listeners on the root node are causing the entire database value to be read to facilitate change tracking. Using "value", "notify_value", "child_changed" and "notify_child_changed" events on the root node are a bad practice because of the significant performance impact. Use "mutated" or "mutations" events instead`)}currentValue=await this.getNodeValue(topEventPath,valueOptions)}topEventData=currentValue;const result=await writeNode()||{};let newTopEventData,modifiedData;if(path===topEventPath){if(options.merge){if(topEventData===null){newTopEventData=value instanceof Array?[]:{}}else{newTopEventData=topEventData instanceof Array?[]:{};Object.keys(topEventData).forEach((key=>{newTopEventData[key]=topEventData[key]}))}}else{newTopEventData=value}modifiedData=newTopEventData}else{const trailPath=path.slice(topEventPath.length).replace(/^\//,"");const trailKeys=PathInfo.getPathKeys(trailPath);if(topEventData===null){newTopEventData=typeof trailKeys[0]==="number"?[]:{}}else{newTopEventData=topEventData instanceof Array?[]:{};Object.keys(topEventData).forEach((key=>{newTopEventData[key]=topEventData[key]}))}modifiedData=newTopEventData;while(trailKeys.length>0){let childKey=trailKeys.shift();if(!options.merge&&trailKeys.length===0){modifiedData[childKey]=value}else{const original=modifiedData[childKey];const shallowCopy=typeof childKey==="number"?[]:{};Object.keys(original).forEach((key=>{shallowCopy[key]=original[key]}));modifiedData[childKey]=shallowCopy}modifiedData=modifiedData[childKey]}}if(options.merge){Object.keys(value).forEach((key=>{modifiedData[key]=value[key]}))}const dataChanges=compareValues(topEventData,newTopEventData);if(dataChanges==="identical"){result.mutations=[];return result}function removeNulls(obj){if(obj===null||typeof obj!=="object"){return obj}Object.keys(obj).forEach((prop=>{const val=obj[prop];if(val===null){delete obj[prop];if(obj instanceof Array){obj.length--}}if(typeof val==="object"){removeNulls(val)}}))}removeNulls(newTopEventData);const indexUpdates=[];indexes.map((index=>({index:index,keys:PathInfo.getPathKeys(index.path)}))).sort(((a,b)=>{if(a.keys.length<b.keys.length){return 1}else if(a.keys.length>b.keys.length){return-1}return 0})).forEach((({index:index})=>{let pathKeys=PathInfo.getPathKeys(topEventPath);let indexPathKeys=PathInfo.getPathKeys(index.path+"/*");let trailKeys=indexPathKeys.slice(pathKeys.length);let oldValue=topEventData;let newValue=newTopEventData;if(trailKeys.length===0){console.assert(pathKeys.length===indexPathKeys.length,"check logic");const p=this.ipc.isMaster?index.handleRecordUpdate(topEventPath,oldValue,newValue):this.ipc.sendRequest({type:"index.update",path:topEventPath,oldValue:oldValue,newValue:newValue});indexUpdates.push(p);return}const getAllIndexUpdates=(path,oldValue,newValue)=>{if(oldValue===null&&newValue===null){return[]}let pathKeys=PathInfo.getPathKeys(path);let indexPathKeys=PathInfo.getPathKeys(index.path+"/*");let trailKeys=indexPathKeys.slice(pathKeys.length);if(trailKeys.length===0){console.assert(pathKeys.length===indexPathKeys.length,"check logic");return[{path:path,oldValue:oldValue,newValue:newValue}]}let results=[];let trailPath="";while(trailKeys.length>0){let subKey=trailKeys.shift();if(subKey==="*"){let allKeys=oldValue===null?[]:Object.keys(oldValue);newValue!==null&&Object.keys(newValue).forEach((key=>{if(allKeys.indexOf(key)<0){allKeys.push(key)}}));allKeys.forEach((key=>{let childPath=PathInfo.getChildPath(trailPath,key);let childValues=getChildValues(key,oldValue,newValue);let subTrailPath=PathInfo.getChildPath(path,childPath);let childResults=getAllIndexUpdates(subTrailPath,childValues.oldValue,childValues.newValue);results=results.concat(childResults)}));break}else{let values=getChildValues(subKey,oldValue,newValue);oldValue=values.oldValue;newValue=values.newValue;if(oldValue===null&&newValue===null){break}trailPath=PathInfo.getChildPath(trailPath,subKey)}}return results};let results=getAllIndexUpdates(topEventPath,oldValue,newValue);results.forEach((result=>{const p=this.ipc.isMaster?index.handleRecordUpdate(result.path,result.oldValue,result.newValue):this.ipc.sendRequest({type:"index.update",path:result.path,oldValue:result.oldValue,newValue:result.newValue});indexUpdates.push(p)}))}));const callSubscriberWithValues=(sub,oldValue,newValue,variables=[])=>{let trigger=true;let type=sub.type;if(type.startsWith("notify_")){type=type.slice("notify_".length)}if(type==="mutated"){return}else if(type==="child_changed"&&(oldValue===null||newValue===null)){trigger=false}else if(type==="value"||type==="child_changed"){let changes=compareValues(oldValue,newValue);trigger=changes!=="identical"}else if(type==="child_added"){trigger=oldValue===null&&newValue!==null}else if(type==="child_removed"){trigger=oldValue!==null&&newValue===null}const pathKeys=PathInfo.getPathKeys(sub.dataPath);variables.forEach((variable=>{const index=pathKeys.indexOf(variable.name);console.assert(index>=0,`Variable "${variable.name}" not found in subscription dataPath "${sub.dataPath}"`);pathKeys[index]=variable.value}));const dataPath=pathKeys.reduce(((path,key)=>PathInfo.getChildPath(path,key)),"");trigger&&this.subscriptions.trigger(sub.type,sub.subscriptionPath,dataPath,oldValue,newValue,options.context)};const prepareMutationEvents=(sub,currentPath,oldValue,newValue,compareResult)=>{const batch=[];const result=compareResult||compareValues(oldValue,newValue);if(result==="identical"){return batch}else if(typeof result==="string"){batch.push({path:currentPath,oldValue:oldValue,newValue:newValue})}else{result.changed.forEach((info=>{const childPath=PathInfo.getChildPath(currentPath,info.key);let childValues=getChildValues(info.key,oldValue,newValue);const childBatch=prepareMutationEvents(sub,childPath,childValues.oldValue,childValues.newValue,info.change);batch.push(...childBatch)}));result.added.forEach((key=>{const childPath=PathInfo.getChildPath(currentPath,key);batch.push({path:childPath,oldValue:null,newValue:newValue[key]})}));if(oldValue instanceof Array&&newValue instanceof Array){result.removed.sort(((a,b)=>a-b))}result.removed.forEach((key=>{const childPath=PathInfo.getChildPath(currentPath,key);batch.push({path:childPath,oldValue:oldValue[key],newValue:null})}))}return batch};if(this.transactionLoggingEnabled&&this.settings.type!=="transaction"){result.mutations=(()=>{const trailPath=path.slice(topEventPath.length).replace(/^\//,"");const trailKeys=PathInfo.getPathKeys(trailPath);let oldValue=topEventData,newValue=newTopEventData;while(trailKeys.length>0){const key=trailKeys.shift();({oldValue:oldValue,newValue:newValue}=getChildValues(key,oldValue,newValue))}const compareResults=compareValues(oldValue,newValue);const fakeSub={event:"mutations",path:path};const batch=prepareMutationEvents(fakeSub,path,oldValue,newValue,compareResults);const mutations=batch.map((m=>({target:PathInfo.getPathKeys(m.path.slice(path.length)),prev:m.oldValue,val:m.newValue})));return mutations})()}const triggerAllEvents=()=>{eventSubscriptions.filter((sub=>!["mutated","mutations","notify_mutated","notify_mutations"].includes(sub.type))).map((sub=>{const keys=PathInfo.getPathKeys(sub.dataPath);return{sub:sub,keys:keys}})).sort(((a,b)=>{if(a.keys.length<b.keys.length){return 1}else if(a.keys.length>b.keys.length){return-1}return 0})).forEach((({sub:sub})=>{const process=(currentPath,oldValue,newValue,variables=[])=>{let trailPath=sub.dataPath.slice(currentPath.length).replace(/^\//,"");let trailKeys=PathInfo.getPathKeys(trailPath);while(trailKeys.length>0){let subKey=trailKeys.shift();if(typeof subKey==="string"&&(subKey==="*"||subKey[0]==="$")){let allKeys=oldValue===null?[]:Object.keys(oldValue).map((key=>oldValue instanceof Array?parseInt(key):key));newValue!==null&&Object.keys(newValue).forEach((key=>{if(newValue instanceof Array){key=parseInt(key)}if(allKeys.indexOf(key)<0){allKeys.push(key)}}));allKeys.forEach((key=>{const childValues=getChildValues(key,oldValue,newValue);const vars=variables.concat({name:subKey,value:key});if(trailKeys.length===0){callSubscriberWithValues(sub,childValues.oldValue,childValues.newValue,vars)}else{process(PathInfo.getChildPath(currentPath,subKey),childValues.oldValue,childValues.newValue,vars)}}));return}else{currentPath=PathInfo.getChildPath(currentPath,subKey);let childValues=getChildValues(subKey,oldValue,newValue);oldValue=childValues.oldValue;newValue=childValues.newValue}}callSubscriberWithValues(sub,oldValue,newValue,variables)};if(sub.type.startsWith("notify_")&&PathInfo.get(sub.eventPath).isAncestorOf(topEventPath)){const isOnParentPath=PathInfo.get(sub.eventPath).isParentOf(topEventPath);const trigger=sub.type==="notify_value"||sub.type==="notify_child_changed"&&(!isOnParentPath||!["added","removed"].includes(dataChanges))||sub.type==="notify_child_removed"&&dataChanges==="removed"&&isOnParentPath||sub.type==="notify_child_added"&&dataChanges==="added"&&isOnParentPath;trigger&&this.subscriptions.trigger(sub.type,sub.subscriptionPath,sub.dataPath,null,null,options.context)}else{process(topEventPath,topEventData,newTopEventData)}}));eventSubscriptions.filter((sub=>["mutated","mutations","notify_mutated","notify_mutations"].includes(sub.type))).forEach((sub=>{let currentPath=path;let trailPath=sub.eventPath.slice(currentPath.length).replace(/^\//,"");let trailKeys=PathInfo.getPathKeys(trailPath);let oldValue=topEventData,newValue=newTopEventData;while(trailKeys.length>0){let subKey=trailKeys.shift();currentPath=PathInfo.getChildPath(currentPath,subKey);let childValues=getChildValues(subKey,oldValue,newValue);oldValue=childValues.oldValue;newValue=childValues.newValue}const batch=prepareMutationEvents(sub,currentPath,oldValue,newValue);if(batch.length===0){return}const isNotifyEvent=sub.type.startsWith("notify_");if(["mutated","notify_mutated"].includes(sub.type)){batch.forEach(((mutation,index)=>{const context=options.context;const prevVal=isNotifyEvent?null:mutation.oldValue;const newVal=isNotifyEvent?null:mutation.newValue;this.subscriptions.trigger(sub.type,sub.subscriptionPath,mutation.path,prevVal,newVal,context)}))}else if(["mutations","notify_mutations"].includes(sub.type)){const values=isNotifyEvent?null:batch.map((m=>({target:PathInfo.getPathKeys(m.path.slice(sub.subscriptionPath.length)),prev:m.oldValue,val:m.newValue})));this.subscriptions.trigger(sub.type,sub.subscriptionPath,sub.subscriptionPath,null,values,options.context)}}))};if(options.waitForIndexUpdates===false){indexUpdates.splice(0)}await Promise.all(indexUpdates);defer(triggerAllEvents);return result}getChildren(path,options){throw new Error(`This method must be implemented by subclass`)}async getNodeValue(path,options){const node=await this.getNode(path,options);return node.value}getNode(path,options){throw new Error(`This method must be implemented by subclass`)}getNodeInfo(path,options){throw new Error(`This method must be implemented by subclass`)}setNode(path,value,options){throw new Error(`This method must be implemented by subclass`)}updateNode(path,updates,options){throw new Error(`This method must be implemented by subclass`)}async transactNode(path,callback,options={no_lock:false,suppress_events:false,context:null}){const useFakeLock=options&&options.no_lock===true;const tid=this.createTid();const lock=useFakeLock?{tid:tid,release(){}}:await this.nodeLocker.lock(path,tid,true,"transactNode");try{let changed=false,changeCallback=()=>{changed=true};if(useFakeLock){this.subscriptions.add(path,"notify_value",changeCallback)}const node=await this.getNode(path,{tid:tid});const checkRevision=node.revision;let newValue;try{newValue=callback(node.value);if(newValue instanceof Promise){newValue=await newValue.catch((err=>{this.debug.error(`Error in transaction callback: ${err.message}`)}))}}catch(err){this.debug.error(`Error in transaction callback: ${err.message}`)}if(typeof newValue==="undefined"){return}if(useFakeLock){this.subscriptions.remove(path,"notify_value",changeCallback)}if(changed){throw new NodeRevisionError(`Node changed`)}const result=await this.setNode(path,newValue,{assert_revision:checkRevision,tid:lock.tid,suppress_events:options.suppress_events,context:options.context});return result}catch(err){if(err instanceof NodeRevisionError){console.warn(`node value changed, running again. Error: ${err.message}`);return this.transactNode(path,callback,options)}else{throw err}}finally{lock.release()}}matchNode(path,criteria,options={tid:undefined}){const tid=options&&options.tid||ID.generate();const checkNode=(path,criteria)=>{if(criteria.length===0){return Promise.resolve(true)}const criteriaKeys=criteria.reduce(((keys,cr)=>{let key=cr.key;if(key.includes("/")){key=key.slice(0,key.indexOf("/"))}if(keys.indexOf(key)<0){keys.push(key)}return keys}),[]);const unseenKeys=criteriaKeys.slice();let isMatch=true;let delayedMatchPromises=[];return this.getChildren(path,{tid:tid,keyFilter:criteriaKeys}).next((childInfo=>{unseenKeys.includes(childInfo.key)&&unseenKeys.splice(unseenKeys.indexOf(childInfo.key),1);const keyCriteria=criteria.filter((cr=>cr.key===childInfo.key)).map((cr=>({op:cr.op,compare:cr.compare})));const keyResult=keyCriteria.length>0?checkChild(childInfo,keyCriteria):{isMatch:true,promises:[]};isMatch=keyResult.isMatch;if(isMatch){delayedMatchPromises.push(...keyResult.promises);const childCriteria=criteria.filter((cr=>cr.key.startsWith(`${childInfo.key}/`))).map((cr=>{const key=cr.key.slice(cr.key.indexOf("/")+1);return{key:key,op:cr.op,compare:cr.compare}}));if(childCriteria.length>0){const childPath=PathInfo.getChildPath(path,childInfo.key);const childPromise=checkNode(childPath,childCriteria).then((isMatch=>({isMatch:isMatch})));delayedMatchPromises.push(childPromise)}}if(!isMatch||unseenKeys.length===0){return false}})).then((()=>{if(isMatch){return Promise.all(delayedMatchPromises).then((results=>{isMatch=results.every((res=>res.isMatch))}))}})).then((()=>{if(!isMatch){return false}isMatch=unseenKeys.every((key=>{const childInfo=new NodeInfo({key:key,exists:false});const childCriteria=criteria.filter((cr=>cr.key.startsWith(`${key}/`))).map((cr=>({op:cr.op,compare:cr.compare})));if(childCriteria.length>0&&!checkChild(childInfo,childCriteria).isMatch){return false}const keyCriteria=criteria.filter((cr=>cr.key===key)).map((cr=>({op:cr.op,compare:cr.compare})));if(keyCriteria.length===0){return true}const result=checkChild(childInfo,keyCriteria);return result.isMatch}));return isMatch})).catch((err=>{this.debug.error(`Error matching on "${path}": `,err);throw err}))};const checkChild=(child,criteria)=>{const promises=[];const isMatch=criteria.every((f=>{let proceed=true;if(f.op==="!exists"||f.op==="=="&&(typeof f.compare==="undefined"||f.compare===null)){proceed=!child.exists}else if(f.op==="exists"||f.op==="!="&&(typeof f.compare==="undefined"||f.compare===null)){proceed=child.exists}else if(!child.exists){proceed=false}else{if(child.address){if(child.valueType===VALUE_TYPES.OBJECT&&["has","!has"].indexOf(f.op)>=0){const op=f.op==="has"?"exists":"!exists";const p=checkNode(child.path,[{key:f.compare,op:op}]).then((isMatch=>({key:child.key,isMatch:isMatch})));promises.push(p);proceed=true}else if(child.valueType===VALUE_TYPES.ARRAY&&["contains","!contains"].indexOf(f.op)>=0){const p=this.getNodeValue(child.path,{tid:tid}).then((arr=>{const isMatch=f.op==="contains"?f.compare instanceof Array?f.compare.every((val=>arr.includes(val))):arr.includes(f.compare):f.compare instanceof Array?!f.compare.some((val=>arr.includes(val))):!arr.includes(f.compare);return{key:child.key,isMatch:isMatch}}));promises.push(p);proceed=true}else if(child.valueType===VALUE_TYPES.STRING){const p=this.getNodeValue(child.path,{tid:tid}).then((val=>({key:child.key,isMatch:this.test(val,f.op,f.compare)})));promises.push(p);proceed=true}else{proceed=false}}else if(child.type===VALUE_TYPES.OBJECT&&["has","!has"].indexOf(f.op)>=0){const has=f.compare in child.value;proceed=has&&f.op==="has"||!has&&f.op==="!has"}else if(child.type===VALUE_TYPES.ARRAY&&["contains","!contains"].indexOf(f.op)>=0){const contains=child.value.indexOf(f.compare)>=0;proceed=contains&&f.op==="contains"||!contains&&f.op==="!contains"}else{let ret=this.test(child.value,f.op,f.compare);if(ret instanceof Promise){promises.push(ret);ret=true}proceed=ret}}return proceed}));return{isMatch:isMatch,promises:promises}};return checkNode(path,criteria)}test(val,op,compare){if(op==="<"){return val<compare}if(op==="<="){return val<=compare}if(op==="=="){return val===compare}if(op==="!="){return val!==compare}if(op===">"){return val>compare}if(op===">="){return val>=compare}if(op==="in"){return compare.indexOf(val)>=0}if(op==="!in"){return compare.indexOf(val)<0}if(op==="like"||op==="!like"){const pattern="^"+compare.replace(/[-[\]{}()+.,\\^$|#\s]/g,"\\$&").replace(/\?/g,".").replace(/\*/g,".*?")+"$";const re=new RegExp(pattern,"i");const isMatch=re.test(val.toString());return op==="like"?isMatch:!isMatch}if(op==="matches"){return compare.test(val.toString())}if(op==="!matches"){return!compare.test(val.toString())}if(op==="between"){return val>=compare[0]&&val<=compare[1]}if(op==="!between"){return val<compare[0]||val>compare[1]}if(op==="has"||op==="!has"){const has=typeof val==="object"&&compare in val;return op==="has"?has:!has}if(op==="contains"||op==="!contains"){const includes=typeof val==="object"&&val instanceof Array&&val.includes(compare);return op==="contains"?includes:!includes}return false}async exportNode(path,write,options={format:"json",type_safe:true}){if(options&&options.format!=="json"){throw new Error(`Only json output is currently supported`)}if(typeof write!=="function"){write=write.write.bind(write)}const stringifyValue=(type,val)=>{const escape=str=>str.replace(/"/g,'\\"').replace(/\n/g,"\\n");if(type===VALUE_TYPES.DATETIME){val=`"${val.toISOString()}"`;if(options.type_safe){val=`{".type":"Date",".val":${val}}`}}else if(type===VALUE_TYPES.STRING){val=`"${escape(val)}"`}else if(type===VALUE_TYPES.ARRAY){val=`[]`}else if(type===VALUE_TYPES.OBJECT){val=`{}`}else if(type===VALUE_TYPES.BINARY){val=`"${escape(ascii85.encode(val))}"`;if(options.type_safe){val=`{".type":"Buffer",".val":${val}}`}}else if(type===VALUE_TYPES.REFERENCE){val=`"${val.path}"`;if(options.type_safe){val=`{".type":"PathReference",".val":${val}}`}}return val};let objStart="",objEnd="";const nodeInfo=await this.getNodeInfo(path);if(!nodeInfo.exists){return write("null")}else if(nodeInfo.type===VALUE_TYPES.OBJECT){objStart="{";objEnd="}"}else if(nodeInfo.type===VALUE_TYPES.ARRAY){objStart="[";objEnd="]"}else{const value=await this.getNodeValue(path);const val=stringifyValue(nodeInfo.type,value);return write(val)}if(objStart){const p=write(objStart);if(p instanceof Promise){await p}}let output="",outputCount=0;const pending=[];await this.getChildren(path).next((childInfo=>{if(childInfo.address){pending.push(childInfo)}else{if(outputCount++>0){output+=","}if(typeof childInfo.key==="string"){output+=`"${childInfo.key}":`}output+=stringifyValue(childInfo.type,childInfo.value)}}));if(output){const p=write(output);if(p instanceof Promise){await p}}while(pending.length>0){const childInfo=pending.shift();let output=outputCount++>0?",":"";const key=typeof childInfo.index==="number"?childInfo.index:childInfo.key;if(typeof key==="string"){output+=`"${key}":`}if(output){const p=write(output);if(p instanceof Promise){await p}}await this.exportNode(PathInfo.getChildPath(path,key),write,options)}if(objEnd){const p=write(objEnd);if(p instanceof Promise){await p}}}async importNode(path,read,options={format:"json",method:"set"}){const chunkSize=256*1024;const maxQueueBytes=1024*1024;let state={data:"",index:0,offset:0,queue:[],queueStartByte:0,timesFlushed:0,get processedBytes(){return this.offset+this.index}};const readNextChunk=async(append=false)=>{let data=await read(chunkSize);if(data===null){if(state.data){throw new Error(`Unexpected EOF at index ${state.offset+state.data.length}`)}else{throw new Error(`Unable to read data from stream`)}}else if(typeof data==="object"){data=(new TextDecoder).decode(data)}if(append){state.data+=data}else{state.offset+=state.data.length;state.data=data;state.index=0}};const readBytes=async length=>{let str="";if(state.index+length>=state.data.length){str=state.data.slice(state.index);length-=str.length;await readNextChunk()}str+=state.data.slice(state.index,state.index+length);state.index+=length;return str};const assertBytes=async length=>{if(state.index+length>state.data.length){await readNextChunk(true)}if(state.index+length>state.data.length){throw new Error(`Not enough data available from stream`)}};const consumeToken=async token=>{const str=await readBytes(token.length);if(str!==token){throw new Error(`Unexpected character "${str[0]}" at index ${state.offset+state.index}, expected "${token}"`)}};const consumeSpaces=async()=>{const spaces=[" ","\t","\r","\n"];while(true){if(state.index>=state.data.length){await readNextChunk()}if(spaces.includes(state.data[state.index])){state.index++}else{break}}};const peekBytes=async length=>{await assertBytes(length);const index=state.index;return state.data.slice(index,index+length)};const peekValueType=async()=>{await consumeSpaces();const ch=await peekBytes(1);switch(ch){case'"':return"string";case"{":return"object";case"[":return"array";case"n":return"null";case"u":return"undefined";case"t":case"f":return"boolean";default:{if(ch==="-"||ch>="0"&&ch<="9"){return"number"}throw new Error(`Unknown value at index ${state.offset+state.index}`)}}};const readString=async()=>{await consumeToken('"');let str="";let i=state.index;while(state.data[i]!=='"'||state.data[i-1]==="\\"){i++;if(i>=state.data.length){str+=state.data.slice(state.index);await readNextChunk();i=0}}str+=state.data.slice(state.index,i);state.index=i+1;return unescape(str)};const readBoolean=async()=>{if(state.data[state.index]==="t"){await consumeToken("true")}else if(state.data[state.index]==="f"){await consumeToken("false")}throw new Error(`Expected true or false at index ${state.offset+state.index}`)};const readNumber=async()=>{let str="";let i=state.index;const nrChars=["-","0","1","2","3","4","5","6","7","8","9",".","e","b","f","x"];while(nrChars.includes(state.data[i])){i++;if(i>=state.data.length){str+=state.data.slice(state.index);await readNextChunk();i=0}}str+=state.data.slice(state.index,i);state.index=i;const nr=str.includes(".")?parseFloat(str):parseInt(str);return nr};const readValue=async()=>{await consumeSpaces();const type=await peekValueType();const value=await(()=>{switch(type){case"string":return readString();case"object":return{};case"array":return[];case"number":return readNumber();case"null":return null;case"undefined":return undefined;case"boolean":return readBoolean()}})();return{type:type,value:value}};const unescape=str=>str.replace(/\\n/g,"\n").replace(/\\"/g,'"');const getTypeSafeValue=(path,obj)=>{const type=obj[".type"];let val=obj[".val"];switch(type){case"Date":val=new Date(val);break;case"Buffer":val=unescape(val);if(val.startsWith("<~")){val=ascii85.decode(val)}else{throw new Error(`Import error: Unexpected encoding for value for value at path "/${path}"`)}break;case"PathReference":val=new PathReference(val);break;default:throw new Error(`Import error: Unsupported type "${type}" for value at path "/${path}"`)}return val};const context={acebase_import_id:ID.generate()};const childOptions={suppress_events:options.suppress_events,context:context};const enqueue=async(target,value)=>{state.queue.push({target:target,value:value});if(state.processedBytes>=state.queueStartByte+maxQueueBytes){const operations=state.queue.reduce(((updates,item)=>{if(item.target.path===path){updates.push({op:options.method==="set"&&state.timesFlushed===0?"set":"update",...item})}else{const parent=updates.find((other=>other.target.isParentOf(item.target)));if(parent){parent.value[item.target.key]=item.value}else{updates.push({op:options.method==="merge"?"update":"set",...item})}}}),[]);state.queueStartBytestate.queueStartByte=state.processedBytes;state.queue=[];state.timesFlushed++}if(target.path===path){}};const importObject=async target=>{await consumeToken("{");await consumeSpaces();let nextChar=await peekBytes(1);if(nextChar==="}"){state.index++;return this.setNode(target.path,{},childOptions)}let childCount=0;let obj={};let flushedBefore=false;const flushObject=async()=>{let p;if(!flushedBefore){flushedBefore=true;p=this.setNode(target.path,obj,childOptions)}else if(Object.keys(obj).length>0){p=this.updateNode(target.path,obj,childOptions)}obj={};if(p){await p}};const promises=[];while(true){await consumeSpaces();const property=await readString();await consumeSpaces();await consumeToken(":");await consumeSpaces();const{value:value,type:type}=await readValue();obj[property]=value;childCount++;if(["object","array"].includes(type)){promises.push(flushObject());if(type==="object"){await importObject(target.child(property))}else{await importArray(target.child(property))}}await consumeSpaces();let nextChar=await peekBytes(1);if(nextChar==="}"){state.index++;break}await consumeToken(",")}const isTypedValue=childCount===2&&".type"in obj&&".val"in obj;if(isTypedValue){const val=getTypeSafeValue(target.path,obj);return this.setNode(target.path,val,childOptions)}promises.push(flushObject());await Promise.all(promises)};const importArray=async target=>{await consumeToken("[");await consumeSpaces();let nextChar=await peekBytes(1);if(nextChar==="]"){state.index++;return this.setNode(target.path,[],childOptions)}let flushedBefore=false;let arr=[];let updates={};const flushArray=async()=>{let p;if(!flushedBefore){flushedBefore=true;p=this.setNode(target.path,arr,childOptions);arr=null}else if(Object.keys(updates).length>0){p=this.updateNode(target.path,updates,childOptions);updates={}}if(p){await p}};const pushChild=(value,index)=>{if(flushedBefore){updates[index]=value}else{arr.push(value)}};const promises=[];let index=0;while(true){await consumeSpaces();const{value:value,type:type}=await readValue();pushChild(value,index);if(["object","array"].includes(type)){promises.push(flushArray());if(type==="object"){await importObject(target.child(index))}else{await importArray(target.child(index))}}await consumeSpaces();let nextChar=await peekBytes(1);if(nextChar==="]"){state.index++;break}await consumeToken(",");index++}promises.push(flushArray());await Promise.all(promises)};const start=async()=>{const{value:value,type:type}=await readValue();if(["object","array"].includes(type)){const target=PathInfo.get(path);if(type==="object"){await importObject(target)}else{await importArray(target)}}else{await this.setNode(path,value,childOptions)}};return start()}setSchema(path,schema){if(typeof schema==="undefined"){throw new TypeError(`schema argument must be given`)}if(schema===null){const i=this._schemas.findIndex((s=>s.path===path));i>=0&&this._schemas.splice(i,1);return}const definition=new SchemaDefinition(schema);let item=this._schemas.find((s=>s.path===path));if(item){item.schema=definition}else{this._schemas.push({path:path,schema:definition});this._schemas.sort(((a,b)=>{const ka=PathInfo.getPathKeys(a.path),kb=PathInfo.getPathKeys(b.path);if(ka.length===kb.length){return 0}return ka.length<kb.length?-1:1}))}}getSchema(path){const item=this._schemas.find((item=>item.path===path));return item?{path:path,schema:item.schema.source,text:item.schema.text}:null}getSchemas(){return this._schemas.map((item=>({path:item.path,schema:item.schema.source,text:item.schema.text})))}validateSchema(path,value,options={updates:false}){let result={ok:true};const pathInfo=PathInfo.get(path);this._schemas.filter((s=>pathInfo.isOnTrailOf(s.path))).every((s=>{if(pathInfo.isDescendantOf(s.path)){const ancestorPath=PathInfo.fillVariables(s.path,path);const trailKeys=pathInfo.keys.slice(PathInfo.getPathKeys(s.path).length);result=s.schema.check(ancestorPath,value,options.updates,trailKeys);return result.ok}const trailKeys=PathInfo.getPathKeys(s.path).slice(pathInfo.keys.length);const partial=options.updates===true&&trailKeys.length===0;const check=(path,value,trailKeys)=>{if(trailKeys.length===0){return s.schema.check(path,value,partial)}else if(value===null){return{ok:true}}const key=trailKeys[0];if(typeof key==="string"&&(key==="*"||key[0]==="$")){if(value===null||typeof value!=="object"){return{ok:true}}let result;Object.keys(value).every((childKey=>{const childPath=PathInfo.getChildPath(path,childKey);const childValue=value[childKey];result=check(childPath,childValue,trailKeys.slice(1));return result.ok}));return result}else{const childPath=PathInfo.getChildPath(path,key);const childValue=value[key];return check(childPath,childValue,trailKeys.slice(1))}};result=check(path,value,trailKeys);return result.ok}));return result}}module.exports={Storage:Storage,StorageSettings:StorageSettings,NodeNotFoundError:NodeNotFoundError,NodeRevisionError:NodeRevisionError,SchemaValidationError:SchemaValidationError,IWriteNodeResult:IWriteNodeResult}},{"./data-index":37,"./ipc":31,"./node-info":33,"./node-value-types":35,"./promise-fs":38,"acebase-core":12}],41:[function(require,module,exports){},{}]},{},[30])(30)})); |