New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

sylviejs

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sylviejs - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

dist/storage-adapter/incremental-indexeddb-adapter.d.ts

106

dist/modules/collection.d.ts

@@ -131,11 +131,11 @@ import { CloneMethods } from "../utils/clone";

constructor(name: string, options?: Partial<CollectionOptions>);
createChange(name: string, op: "U" | "I" | "R", obj: object, old?: object): void;
insertMeta(obj: CollectionDocument): void;
updateMeta(obj: CollectionDocument): CollectionDocument;
createInsertChange(obj: CollectionDocument): void;
createChange<T extends Partial<CollectionDocument>>(name: string, op: "U" | "I" | "R", obj: T, old?: T): void;
insertMeta<T extends Partial<CollectionDocument>>(obj: T): void;
updateMeta<T extends CollectionDocument>(obj: T): T;
createInsertChange<T extends Partial<CollectionDocument>>(obj: T): void;
createUpdateChange(obj: CollectionDocument, old: CollectionDocument): void;
insertMetaWithChange(obj: CollectionDocument): void;
updateMetaWithChange(obj: CollectionDocument, old: CollectionDocument): CollectionDocument;
addAutoUpdateObserver(object: object): void;
removeAutoUpdateObserver(object: object): void;
insertMetaWithChange<T extends Partial<CollectionDocument>>(obj: T): void;
updateMetaWithChange<T extends CollectionDocument>(obj: T, old: T): T;
addAutoUpdateObserver<T extends CollectionDocument>(object: T): void;
removeAutoUpdateObserver<T extends object>(object: T): void;
/**

@@ -145,3 +145,3 @@ * Adds a named collection transform to the collection

* @param {array} transform - an array of transformation 'step' objects to save into the collection
* @memberof Collection
* @example

@@ -165,3 +165,2 @@ * users.addTransform('progeny', [

* @param {string} name - name of the transform to lookup.
* @memberof Collection
*/

@@ -175,3 +174,3 @@ getTransform(name: string): (Record<string, any> & {

* @param {object} transform - a transformation object to save into collection
* @memberof Collection
*/

@@ -184,3 +183,3 @@ setTransform(name: string, transform: (Record<string, any> & {

* @param {string} name - name of collection transform to remove
* @memberof Collection
*/

@@ -191,3 +190,3 @@ removeTransform(name: string): void;

};
findObject(template: Record<string, any>): any;
findObject(template: Record<string, any>): ColT;
findObjects(template: Record<string, any>): ColT[];

@@ -199,3 +198,3 @@ ttlDaemonFuncGen(): () => void;

* @param {int} interval - time (in ms) to clear collection of aged documents.
* @memberof Collection
*/

@@ -210,3 +209,3 @@ setTTL(age: number, interval: number): void;

* @param {boolean} options.adaptiveBinaryIndices - collection indices will be actively rebuilt rather than lazily
* @memberof Collection
*/

@@ -220,3 +219,3 @@ configureOptions: (options?: {

* @param {boolean=} force - (Optional) flag indicating whether to construct index immediately
* @memberof Collection
*/

@@ -231,3 +230,3 @@ ensureIndex(property: string, force?: boolean): void;

* @returns {string[]} array of index names where problems were found.
* @memberof Collection
* @example

@@ -255,3 +254,3 @@ * // check all indices on a collection, returns array of invalid index names

* @returns {boolean} whether the index was found to be valid (before optional correcting).
* @memberof Collection
* @example

@@ -287,3 +286,3 @@ * // full test

* @param {boolean} force - whether to force rebuild of existing lazy binary indices
* @memberof Collection
*/

@@ -303,3 +302,3 @@ ensureAllIndexes(force?: boolean): void;

* @returns {number} number of documents in the collection
* @memberof Collection
*/

@@ -323,3 +322,2 @@ count: (query?: Record<string, any>) => number;

* @returns {DynamicView} reference to the dynamic view added
* @memberof Collection
* @example

@@ -336,3 +334,2 @@ * var pview = users.addDynamicView('progeny');

* @param {string} name - name of dynamic view to remove
* @memberof Collection
**/

@@ -344,3 +341,2 @@ removeDynamicView(name: any): void;

* @returns {DynamicView} A reference to the dynamic view with that name
* @memberof Collection
**/

@@ -354,3 +350,2 @@ getDynamicView(name: any): DynamicView<ColT>;

* @param {function} updateFunction - update function to run against filtered documents
* @memberof Collection
*/

@@ -362,3 +357,2 @@ findAndUpdate(filterObject: any, updateFunction: any): void;

* @param {object} filterObject - 'mongo-like' query object
* @memberof Collection
*/

@@ -373,3 +367,2 @@ findAndRemove(filterObject?: Record<string, any>): void;

* @returns {(object|array)} document or documents inserted
* @memberof Collection
* @example

@@ -385,3 +378,3 @@ * users.insert({

*/
insert(doc: any, overrideAdaptiveIndices?: boolean): any;
insert<T extends CollectionDocument | CollectionDocument[]>(doc: T, overrideAdaptiveIndices?: boolean): T;
/**

@@ -393,8 +386,7 @@ * Adds a single object, ensures it has meta properties, clone it if necessary, etc.

*/
insertOne(doc: any, bulkInsert?: boolean): any;
insertOne<T extends CollectionDocument>(doc: T, bulkInsert?: boolean): T | undefined;
/**
* Empties the collection.
* Empties the collection of all data but leaves indexes and options intact by default.
* @param {object=} options - configure clear behavior
* @param {bool=} [options.removeIndices=false] - whether to remove indices in addition to data
* @memberof Collection
*/

@@ -406,4 +398,4 @@ clear(options?: {

* Updates an object and notifies collection that the document has changed.
* @param {object} doc - document to update within the collection
* @memberof Collection
* @param {CollectionDocument} doc - document to update within the collection
* @returns the document that was updated
*/

@@ -420,3 +412,3 @@ update(doc: CollectionDocument | CollectionDocument[]): any;

* @param {function} updateFunction - update function to run against filtered documents
* @memberof Collection
*/

@@ -428,3 +420,3 @@ updateWhere(filterFunction: any, updateFunction: any): void;

* @param {function|object} query - query object to filter on
* @memberof Collection
*/

@@ -446,3 +438,3 @@ removeWhere(query: ((...args: any[]) => any) | Record<string, any>): void;

* @param {object | array | number} newDoc - document(s) to remove from collection. If number, remove by id
* @memberof Collection
* @returns CollectionDocument | null - null if document not found, otherwise removed document. Array of new documents is not returned

@@ -457,3 +449,3 @@ */

* or an array if 'returnPosition' was passed.
* @memberof Collection
*/

@@ -523,3 +515,3 @@ get(id: number, returnPosition?: boolean): object | Array<any> | null;

* @returns {object} document matching the value passed
* @memberof Collection
*/

@@ -531,5 +523,5 @@ by(field: string, value?: string): any;

* @returns {(object|null)} First matching document, or null if none
* @memberof Collection
*/
findOne(query?: {}): any;
findOne(query?: {}): ColT;
/**

@@ -542,3 +534,3 @@ * Chain method, used for beginning a series of chained find() and/or view() operations

* @returns {ResultSet} (this) resultset, or data array if any map or join functions where called
* @memberof Collection
*/

@@ -552,3 +544,3 @@ chain(transform?: ChainTransform, parameters?: any | any[]): ResultSet<ColT> | any;

* @returns {array} Array of matching documents
* @memberof Collection
*/

@@ -580,3 +572,3 @@ find(query?: Record<string, any>): ColT[];

* @returns {array} all documents which pass your filter function
* @memberof Collection
*/

@@ -590,3 +582,3 @@ where(fun: any): ColT[];

* @returns {data} The result of your mapReduce operation
* @memberof Collection
*/

@@ -606,3 +598,3 @@ mapReduce: (mapFunction: any, reduceFunction: any) => any;

* @returns {ResultSet} Result of the mapping operation
* @memberof Collection
*/

@@ -616,3 +608,3 @@ eqJoin(joinData: ColT[] | ResultSet<ColT> | Collection<ColT>, leftJoinProp: string, rightJoinProp: string, mapFun: () => void, dataOptions: {

* (Staging API) create a stage and/or retrieve it
* @memberof Collection
*/

@@ -622,3 +614,3 @@ getStage(name: string): CollectionDocument;

* (Staging API) create a copy of an object and insert it into a stage
* @memberof Collection
*/

@@ -631,19 +623,19 @@ stage(stageName: string, obj: CollectionDocument): any;

* @param {string} message
* @memberof Collection
*/
commitStage(stageName: string, message: string): void;
/**
* @memberof Collection
*/
extract(field: any): any[];
/**
* @memberof Collection
*/
max(field: any): any;
/**
* @memberof Collection
*/
min(field: any): any;
/**
* @memberof Collection
*/

@@ -655,3 +647,3 @@ maxRecord(field: any): {

/**
* @memberof Collection
*/

@@ -663,3 +655,3 @@ minRecord(field: any): {

/**
* @memberof Collection
*/

@@ -672,3 +664,3 @@ extractNumerical(field: any): number[];

* @returns {number} average of property in all docs in the collection
* @memberof Collection
*/

@@ -678,3 +670,3 @@ avg(field: any): number;

* Calculate standard deviation of a field
* @memberof Collection
* @param {string} field

@@ -684,3 +676,3 @@ */

/**
* @memberof Collection
* @param {string} field

@@ -690,3 +682,3 @@ */

/**
* @memberof Collection
* @param {string} field - property name

@@ -693,0 +685,0 @@ */

@@ -346,2 +346,3 @@ import { FsAdapter } from "../storage-adapter/fs-adapter";

close(callback: any): void;
closeAsync(): Promise<void>;
/**-------------------------+

@@ -491,2 +492,5 @@ | Changes API |

}) => void): void;
deleteDatabaseAsync(): Promise<{
success: true;
}>;
/**

@@ -493,0 +497,0 @@ * autosaveDirty - check whether any collections are 'dirty' meaning we need to save (entire) database

import { SylvieCatalog } from "./crypted-indexeddb-adapter/sylvie-catalog";
import { PersistenceAdapter } from "./persistence-adapter";
import { AsyncPersistenceAdapter, PersistenceAdapter } from "./persistence-adapter";
interface CryptedIndexedAdapterOptions {
appname: string;
closeAfterSave: boolean;

@@ -21,8 +22,8 @@ secret: string;

*
* @param {string} appname - (Optional) Application name context can be used to distinguish subdomains, 'loki' by default
* @param {CryptedIndexedAdapterOptions} options Configuration options for the adapter
* @param {string} options.appname - (Optional) Application name context can be used to distinguish subdomains, 'sylvie' by default
* @param {boolean} options.closeAfterSave Whether the indexedDB database should be closed after saving.
* @param {boolean} options.secret The password to encrypt with.
*/
export declare class CryptedIndexedDBAdapter implements PersistenceAdapter {
export declare class CryptedIndexedDBAdapter implements PersistenceAdapter, AsyncPersistenceAdapter {
#private;

@@ -34,5 +35,18 @@ isAsync: true;

mode: string;
constructor(appname: string, options?: Partial<CryptedIndexedAdapterOptions>);
setSecret(secret: string): void;
constructor(options?: Partial<CryptedIndexedAdapterOptions>);
/**
* Sets a password for use on future load and save of the database.
* Note that this does not re-encrypt the database with the new password. Use changePassword() for that.
* @param secret
* @example
* const db = new Sylvie(TEST_DB_NAME, {
* adapter: new CryptedIndexedDBAdapter();
* });
*
* adapter.usePassword("newpassword");
*
* await newDb.loadDatabaseAsync({});
*/
usePassword(secret: string): void;
/**
* Retrieves a serialized db string from the catalog.

@@ -53,2 +67,25 @@ *

/**
* Retrieves a serialized db string from the catalog, returns a promise to a string of the serialized database.
* @param dbname
* @returns {Promise<string>} A promise to a string of the serialized database.
* @example
* const db = new Sylvie(TEST_DB_NAME, {
* adapter: new CryptedIndexedDBAdapter();
* });
* await db.loadDatabaseAsync({});
* // db is now ready to use
* // you can also chain the promises
* await db.loadDatabaseAsync({}).then(() => {
* // db is now ready to use
* });
* // or use async await syntax
* await db.loadDatabaseAsync({});
* // db is now ready to use
* @memberof CryptedIndexedDBAdapter
* @throws {Error} If the database is not found.
* @throws {Error} If the database is not decrypted successfully.
* @throws {Error} If the database is not deserialized successfully.
*/
loadDatabaseAsync: (dbname: string) => Promise<string>;
/**
* Saves a serialized db to the catalog.

@@ -74,2 +111,5 @@ *

}) => void) => void;
saveDatabaseAsync(dbname: string, dbstring: string): Promise<{
success: true;
}>;
/**

@@ -95,3 +135,19 @@ * Deletes a serialized db from the catalog.

}) => any) => void;
deleteDatabaseAsync(dbname: string): Promise<{
success: true;
}>;
/**
* Changes the password of a database and re-encrypts the database with the new password.
* @param {string} dbName The name of the database to change the password of.
* @param {string} newPassword The new password to encrypt the database with.
* @memberof CryptedIndexedDBAdapter
* @returns {Promise<void>} A promise that resolves when the password has been changed.
* @throws {Error} If the adapter is not open.
* @example
* await adapter.changePassword("mydb", "newpassword");
* // The database "mydb" is now encrypted with the password "newpassword".
* // The old password will no longer work.
*/
changePassword(dbname: string, newPassword: string): Promise<void>;
/**
* Removes all database partitions and pages with the base filename passed in.

@@ -98,0 +154,0 @@ * This utility method does not (yet) guarantee async deletions will be completed before returning

@@ -1,2 +0,2 @@

var L=Object.defineProperty;var d=(s,t)=>L(s,"name",{value:t,configurable:!0});var E=(s,t,e)=>{if(!t.has(s))throw TypeError("Cannot "+e)};var v=(s,t,e)=>(E(s,t,"read from private field"),e?e.call(s):t.get(s)),x=(s,t,e)=>{if(t.has(s))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(s):t.set(s,e)},C=(s,t,e,o)=>(E(s,t,"write to private field"),o?o.call(s,e):t.set(s,e),e);var P=(s,t,e)=>(E(s,t,"access private method"),e);var h=(s,t,e)=>new Promise((o,n)=>{var r=c=>{try{i(e.next(c))}catch(l){n(l)}},a=c=>{try{i(e.throw(c))}catch(l){n(l)}},i=c=>c.done?o(c.value):Promise.resolve(c.value).then(r,a);i((e=e.apply(s,t)).next())});function O(s){if(s.length%4!==0)throw new Error("Unable to parse base64 string (invalid length).");let t=s.indexOf("=");if(t!==-1&&t<s.length-2)throw new Error("Unable to parse base64 string (octets).");let e=s.endsWith("==")?2:s.endsWith("=")?1:0,o=s.length,n=new Uint8Array(3*(o/4)),r;for(let a=0,i=0;a<o;a+=4,i+=3)r=S(s.charCodeAt(a))<<18|S(s.charCodeAt(a+1))<<12|S(s.charCodeAt(a+2))<<6|S(s.charCodeAt(a+3)),n[i]=r>>16,n[i+1]=r>>8&255,n[i+2]=r&255;return n.subarray(0,n.length-e)}d(O,"base64ToBytes");var y=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","_","-"],B=(()=>{let t=new Uint8Array(256);for(let e=0;e<256;++e)t[e]=255;return y.forEach((e,o)=>{t[e.charCodeAt(0)]=o}),t["=".charCodeAt(0)]=0,t})();function S(s){if(s>=B.length)throw new Error("Unable to parse base64 string (code beyond length).");let t=B[s];if(t===255)throw new Error("Unable to parse base64 string (invalid code).");return t}d(S,"getBase64Code");function $(s){let t="",e,o=s.length;for(e=2;e<o;e+=3)t+=y[s[e-2]>>2],t+=y[(s[e-2]&3)<<4|s[e-1]>>4],t+=y[(s[e-1]&15)<<2|s[e]>>6],t+=y[s[e]&63];return e===o+1&&(t+=y[s[e-2]>>2],t+=y[(s[e-2]&3)<<4],t+="=="),e===o&&(t+=y[s[e-2]>>2],t+=y[(s[e-2]&3)<<4|s[e-1]>>4],t+=y[(s[e-1]&15)<<2],t+="="),t}d($,"bytesToBase64");var j=d(s=>{let t=new TextEncoder;return window.crypto.subtle.importKey("raw",t.encode(s),"PBKDF2",!1,["deriveKey"])},"getPasswordKey"),V=d((s,t,e)=>window.crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:25e4,hash:"SHA-256"},s,{name:"AES-GCM",length:256},!1,e),"deriveKey");function I(s,t){return h(this,null,function*(){try{let e=window.crypto.getRandomValues(new Uint8Array(16)),o=window.crypto.getRandomValues(new Uint8Array(12)),n=yield j(t),r=yield V(n,e,["encrypt"]),a=yield window.crypto.subtle.encrypt({name:"AES-GCM",iv:o},r,new TextEncoder().encode(s)),i=new Uint8Array(a),c=new Uint8Array(e.byteLength+o.byteLength+i.byteLength);return c.set(e,0),c.set(o,e.byteLength),c.set(i,e.byteLength+o.byteLength),$(c)}catch(e){throw console.log(`Encryption Error - ${e}`),e}})}d(I,"encryptData");function U(s,t){return h(this,null,function*(){try{let e=O(s),o=e.slice(0,16),n=e.slice(16,16+12),r=e.slice(16+12),a=yield j(t),i=yield V(a,o,["decrypt"]),c=yield window.crypto.subtle.decrypt({name:"AES-GCM",iv:n},i,r);return new TextDecoder().decode(c)}catch(e){throw console.log(`Decryption Error - ${e}`),e}})}d(U,"decryptData");var g=class{constructor(t){this.db=null,this.initializeCatalog().then(e=>{typeof t=="function"&&t(e)}).catch(e=>{throw console.log(e),e})}openCatalog(){let t=indexedDB.open("SylvieCatalog",1);return t.onupgradeneeded=({target:e})=>{let o=e.result;if(o.objectStoreNames.contains("SylvieAKV")&&o.deleteObjectStore("SylvieAKV"),!o.objectStoreNames.contains("SylvieAKV")){let n=o.createObjectStore("SylvieAKV",{keyPath:"id",autoIncrement:!0});n.createIndex("app","app",{unique:!1}),n.createIndex("key","key",{unique:!1}),n.createIndex("appkey","appkey",{unique:!0})}},t}initializeCatalog(){return h(this,null,function*(){let t=this,e=this.openCatalog();return new Promise((o,n)=>{e.onsuccess=({target:r})=>{t.db=r.result,o(t)},e.onerror=r=>{n(r)}})})}getAppKeyAsync(t,e){return h(this,null,function*(){let r=this.db.transaction(["SylvieAKV"],"readonly").objectStore("SylvieAKV").index("appkey"),a=`${t},${e}`,i=r.get(a);return new Promise((c,l)=>{i.onsuccess=({target:u})=>{let p=u.result;(p===null||typeof p=="undefined")&&(p={id:0,success:!1}),c(p)},i.onerror=u=>{l(u)}})})}setAppKeyAsync(t,e,o){return h(this,null,function*(){let r=this.db.transaction(["SylvieAKV"],"readwrite").objectStore("SylvieAKV"),a=r.index("appkey"),i=`${t},${e}`,c=a.get(i);return new Promise((l,u)=>{c.onsuccess=({target:p})=>{let f=p.result;f==null?f={app:t,key:e,appkey:`${t},${e}`,val:o}:f.val=o;let m=r.put(f);m.onerror=()=>{u({success:!1,error:m.error}),console.error("SylvieCatalog.setAppKey (set) onerror"),console.error(c.error)},m.onsuccess=()=>{l({success:!0})}},c.onerror=()=>{u({success:!1,error:c.error}),console.error("SylvieCatalog.setAppKey (get) onerror"),console.error(c.error)}})})}deleteAppKeyAsync(t){let n=this.db.transaction(["SylvieAKV"],"readwrite").objectStore("SylvieAKV").delete(t);return new Promise((r,a)=>{n.onsuccess=()=>{r({success:!0})},n.onerror=i=>{a({success:!1,error:i}),console.error("SylvieCatalog.deleteAppKey raised onerror"),console.error(n.error)}})}getAppKeys(t,e){let r=this.db.transaction(["SylvieAKV"],"readonly").objectStore("SylvieAKV").index("app"),a=IDBKeyRange.only(t),i=r.openCursor(a),c=[];i.onsuccess=((l,u)=>()=>{let p=i.result;if(p){let f=p.value;l.push(f),p.continue()}else typeof u=="function"?u(l):console.log(l)})(c,e),i.onerror=(l=>u=>{typeof l=="function"?l(null):(console.error("SylvieCatalog.getAppKeys raised onerror"),console.error(u))})(e)}getAllKeys(t){let n=this.db.transaction(["SylvieAKV"],"readonly").objectStore("SylvieAKV").openCursor(),r=[];n.onsuccess=((a,i)=>()=>{let c=n.result;if(c){let l=c.value;a.push(l),c.continue()}else typeof i=="function"?i(a):console.log(a)})(r,t),n.onerror=(a=>i=>{typeof a=="function"&&a(null)})(t)}};d(g,"SylvieCatalog");var A=typeof window!="undefined"&&!!window.__loki_idb_debug;A&&console.log("DEBUG: Running crypted-indexeddb-adapter in DEBUG mode");if(!window.crypto.subtle)throw alert("Required crypto lib is not availible, are you using SSL?"),new Error("Required crypto lib is not availible");var w,K,D,R,b=class{constructor(t,e){x(this,D);x(this,w,void 0);x(this,K,d(()=>{this.catalog&&this.catalog.db&&(this.catalog.db.close(),this.catalog.db=null)},"#closeDatabase"));this.loadDatabase=d((t,e)=>{if(A&&console.debug("loading database"),this.catalog===null||this.catalog.db===null){this.catalog=new g(o=>{this.catalog=o,this.loadDatabase(t,e)});return}this.catalog.getAppKeyAsync(this.app,t).then(o=>{let{success:n}=o;if(n===!1){e(null);return}else{let{val:r}=o;typeof e=="function"?U(r,v(this,w)).then(i=>{A&&console.debug(`DECRYPTED STRING: ${i}`),e(i)}).catch(i=>{e(i)}):console.log(r)}})},"loadDatabase");this.saveDatabase=d((t,e,o)=>{A&&console.debug(`in saveDatabase(${t}, ${e}, ${o})`);let n=d(r=>{r==null||typeof r=="object"&&Object.hasOwn(r,"success")&&r&&r.success===!0?o(void 0):o(new Error("Error saving database: "+r)),this.options.closeAfterSave===!0&&v(this,K).call(this)},"saveCallback");if(this.catalog===null||this.catalog.db===null){this.catalog=new g(()=>{this.saveDatabase(t,e,n)});return}I(e,v(this,w)).then(r=>{A&&console.debug(`ENCRYPTED STRING: ${r}`),this.catalog.setAppKeyAsync(this.app,t,r).then(a=>{o(a)}).catch(a=>{o(a)})}).catch(r=>{o(r)})},"saveDatabase");this.deleteDatabase=d((t,e)=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new g(o=>{this.catalog=o,this.deleteDatabase(t,e)});return}this.catalog.getAppKeyAsync(this.app,t).then(o=>{let n=o.id;n!==0&&this.catalog.deleteAppKeyAsync(n).then(r=>{typeof e=="function"&&e(r)}).catch(r=>{typeof e=="function"&&e({success:!1,error:r})})}).catch(o=>{typeof e=="function"&&e({success:!1,error:o})})},"deleteDatabase");this.deleteDatabasePartitions=d(t=>{this.getDatabaseList(e=>{e.forEach(o=>{o.startsWith(t)&&this.deleteDatabase(o)})})},"deleteDatabasePartitions");this.getDatabaseList=d(t=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new g(e=>{this.catalog=e,this.getDatabaseList(t)});return}this.catalog.getAppKeys(this.app,e=>{let o=[];for(let n=0;n<e.length;n++)o.push(e[n].key);typeof t=="function"?t(o):o.forEach(n=>{console.log(n)})})},"getDatabaseList");this.getDatabaseListAsync=d(()=>new Promise((t,e)=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new g(o=>{this.catalog=o,this.getDatabaseListAsync()});return}this.catalog.getAppKeys(this.app,o=>{let n=[];for(let r=0;r<o.length;r++)n.push(o[r].key);t(n)})}),"getDatabaseListAsync");this.getCatalogSummary=d(t=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new g(e=>{this.catalog=e,this.getCatalogSummary(t)});return}this.catalog.getAllKeys(e=>{let o=[],n,r,a,i,c;for(let l=0;l<e.length;l++)n=e[l],a=n.app||"",i=n.key||"",c=n.val||"",r=a.length*2+i.length*2+c.length+1,o.push({app:n.app,key:n.key,size:r});typeof t=="function"?t(o):o.forEach(l=>{console.log(l)})})},"getCatalogSummary");if(A&&console.log("Initialized crypted-indexeddb-adapter"),this.app="loki",this.options=e||{},typeof t!="undefined"&&(this.app=t),this.catalog=null,!P(this,D,R).call(this))throw new Error("IndexedDB does not seem to be supported for your environment");e.secret&&C(this,w,e.secret)}setSecret(t){C(this,w,t)}};d(b,"CryptedIndexedDBAdapter"),w=new WeakMap,K=new WeakMap,D=new WeakSet,R=d(function(){return!!(typeof indexedDB!="undefined"&&indexedDB)},"#checkIDBAvailability");typeof window!="undefined"&&Object.assign(window,{IndexedDBAdapter:b,CryptedIndexedDBAdapter:b});export{b as CryptedIndexedDBAdapter};
var j=Object.defineProperty;var l=(r,t)=>j(r,"name",{value:t,configurable:!0});var B=(r,t,e)=>{if(!t.has(r))throw TypeError("Cannot "+e)};var A=(r,t,e)=>(B(r,t,"read from private field"),e?e.call(r):t.get(r)),v=(r,t,e)=>{if(t.has(r))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(r):t.set(r,e)},D=(r,t,e,s)=>(B(r,t,"write to private field"),s?s.call(r,e):t.set(r,e),e);var K=(r,t,e)=>(B(r,t,"access private method"),e);var d=(r,t,e)=>new Promise((s,n)=>{var o=c=>{try{i(e.next(c))}catch(u){n(u)}},a=c=>{try{i(e.throw(c))}catch(u){n(u)}},i=c=>c.done?s(c.value):Promise.resolve(c.value).then(o,a);i((e=e.apply(r,t)).next())});function L(r){if(r.length%4!==0)throw new Error("Unable to parse base64 string (invalid length).");let t=r.indexOf("=");if(t!==-1&&t<r.length-2)throw new Error("Unable to parse base64 string (octets).");let e=r.endsWith("==")?2:r.endsWith("=")?1:0,s=r.length,n=new Uint8Array(3*(s/4)),o;for(let a=0,i=0;a<s;a+=4,i+=3)o=E(r.charCodeAt(a))<<18|E(r.charCodeAt(a+1))<<12|E(r.charCodeAt(a+2))<<6|E(r.charCodeAt(a+3)),n[i]=o>>16,n[i+1]=o>>8&255,n[i+2]=o&255;return n.subarray(0,n.length-e)}l(L,"base64ToBytes");var f=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","_","-"],T=(()=>{let t=new Uint8Array(256);for(let e=0;e<256;++e)t[e]=255;return f.forEach((e,s)=>{t[e.charCodeAt(0)]=s}),t["=".charCodeAt(0)]=0,t})();function E(r){if(r>=T.length)throw new Error("Unable to parse base64 string (code beyond length).");let t=T[r];if(t===255)throw new Error("Unable to parse base64 string (invalid code).");return t}l(E,"getBase64Code");function q(r){let t="",e,s=r.length;for(e=2;e<s;e+=3)t+=f[r[e-2]>>2],t+=f[(r[e-2]&3)<<4|r[e-1]>>4],t+=f[(r[e-1]&15)<<2|r[e]>>6],t+=f[r[e]&63];return e===s+1&&(t+=f[r[e-2]>>2],t+=f[(r[e-2]&3)<<4],t+="=="),e===s&&(t+=f[r[e-2]>>2],t+=f[(r[e-2]&3)<<4|r[e-1]>>4],t+=f[(r[e-1]&15)<<2],t+="="),t}l(q,"bytesToBase64");var O=l(r=>{let t=new TextEncoder;return window.crypto.subtle.importKey("raw",t.encode(r),"PBKDF2",!1,["deriveKey"])},"getPasswordKey"),U=l((r,t,e)=>window.crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:25e4,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,e),"deriveKey");function R(r,t){return d(this,null,function*(){try{let e=window.crypto.getRandomValues(new Uint8Array(16)),s=window.crypto.getRandomValues(new Uint8Array(12)),n=yield O(t),o=yield U(n,e,["encrypt"]),a=yield window.crypto.subtle.encrypt({name:"AES-GCM",iv:s},o,new TextEncoder().encode(r)),i=new Uint8Array(a),c=new Uint8Array(e.byteLength+s.byteLength+i.byteLength);return c.set(e,0),c.set(s,e.byteLength),c.set(i,e.byteLength+s.byteLength),q(c)}catch(e){throw console.log(`Encryption Error - ${e}`),e}})}l(R,"encryptData");function I(r,t){return d(this,null,function*(){try{let e=L(r),s=e.slice(0,16),n=e.slice(16,16+12),o=e.slice(16+12),a=yield O(t),i=yield U(a,s,["decrypt"]),c=yield window.crypto.subtle.decrypt({name:"AES-GCM",iv:n},i,o);return new TextDecoder().decode(c)}catch(e){throw console.log(`Decryption Error - ${e}`),e}})}l(I,"decryptData");var m,V,h=class{constructor(t){v(this,m);this.db=null,t&&K(this,m,V).call(this).then(e=>{typeof t=="function"&&t(e)}).catch(e=>{throw console.log(e),e})}initialize(){return new Promise((t,e)=>{K(this,m,V).call(this).then(s=>{t(s)}).catch(s=>{console.log(s),e(s)})})}openCatalog(){let t=indexedDB.open("SylvieCatalog",1);return t.onupgradeneeded=({target:e})=>{let s=e.result;if(s.objectStoreNames.contains("SylvieAKV")&&s.deleteObjectStore("SylvieAKV"),!s.objectStoreNames.contains("SylvieAKV")){let n=s.createObjectStore("SylvieAKV",{keyPath:"id",autoIncrement:!0});n.createIndex("app","app",{unique:!1}),n.createIndex("key","key",{unique:!1}),n.createIndex("appkey","appkey",{unique:!0})}},t}getAppKeyAsync(t,e){return d(this,null,function*(){let o=this.db.transaction(["SylvieAKV"],"readonly").objectStore("SylvieAKV").index("appkey"),a=`${t},${e}`,i=o.get(a);return new Promise((c,u)=>{i.onsuccess=({target:g})=>{let y=g.result;(y===null||typeof y=="undefined")&&(y={id:0,success:!1}),c(y)},i.onerror=g=>{u(g)}})})}setAppKeyAsync(t,e,s){return d(this,null,function*(){let o=this.db.transaction(["SylvieAKV"],"readwrite").objectStore("SylvieAKV"),a=o.index("appkey"),i=`${t},${e}`,c=a.get(i);return new Promise((u,g)=>{c.onsuccess=({target:y})=>{let b=y.result;b==null?b={app:t,key:e,appkey:`${t},${e}`,val:s}:b.val=s;let C=o.put(b);C.onerror=()=>{g({success:!1,error:C.error}),console.error("SylvieCatalog.setAppKey (set) onerror"),console.error(c.error)},C.onsuccess=()=>{u({success:!0})}},c.onerror=()=>{g({success:!1,error:c.error}),console.error("SylvieCatalog.setAppKey (get) onerror"),console.error(c.error)}})})}deleteAppKeyAsync(t){let n=this.db.transaction(["SylvieAKV"],"readwrite").objectStore("SylvieAKV").delete(t);return new Promise((o,a)=>{n.onsuccess=()=>{o({success:!0})},n.onerror=i=>{a({success:!1,error:i}),console.error("SylvieCatalog.deleteAppKey raised onerror"),console.error(n.error)}})}getAppKeys(t,e){let o=this.db.transaction(["SylvieAKV"],"readonly").objectStore("SylvieAKV").index("app"),a=IDBKeyRange.only(t),i=o.openCursor(a),c=[];i.onsuccess=((u,g)=>()=>{let y=i.result;if(y){let b=y.value;u.push(b),y.continue()}else typeof g=="function"?g(u):console.log(u)})(c,e),i.onerror=(u=>g=>{typeof u=="function"?u(null):(console.error("SylvieCatalog.getAppKeys raised onerror"),console.error(g))})(e)}getAllKeys(t){let n=this.db.transaction(["SylvieAKV"],"readonly").objectStore("SylvieAKV").openCursor(),o=[];n.onsuccess=((a,i)=>()=>{let c=n.result;if(c){let u=c.value;a.push(u),c.continue()}else typeof i=="function"?i(a):console.log(a)})(o,t),n.onerror=(a=>i=>{typeof a=="function"&&a(null)})(t)}};l(h,"SylvieCatalog"),m=new WeakSet,V=l(function(){return d(this,null,function*(){let t=this,e=this.openCatalog();return new Promise((s,n)=>{e.onsuccess=({target:o})=>{t.db=o.result,s(t)},e.onerror=o=>{n(o)}})})},"#initializeCatalog");var w=typeof window!="undefined"&&!!window.__loki_idb_debug;w&&console.log("DEBUG: Running crypted-indexeddb-adapter in DEBUG mode");if(!window.crypto.subtle)throw alert("Required crypto lib is not availible, are you using SSL?"),new Error("Required crypto lib is not availible");var p,S,P,$,x=class{constructor(t){v(this,P);v(this,p,void 0);v(this,S,l(()=>{this.catalog&&this.catalog.db&&(this.catalog.db.close(),this.catalog.db=null)},"#closeDatabase"));this.loadDatabase=l((t,e)=>{if(w&&console.debug("loading database"),this.catalog===null||this.catalog.db===null){this.catalog=new h(s=>{this.catalog=s,this.loadDatabase(t,e)});try{this.catalog.initialize().then(s=>{this.catalog=s})}catch(s){console.log(s)}return}this.catalog.getAppKeyAsync(this.app,t).then(s=>{let{success:n}=s;if(n===!1){e(null);return}else{let{val:o}=s;typeof e=="function"?I(o,A(this,p)).then(i=>{w&&console.debug(`DECRYPTED STRING: ${i}`),e(i)}).catch(i=>{e(i)}):console.log(o)}})},"loadDatabase");this.loadDatabaseAsync=l(t=>d(this,null,function*(){return w&&console.debug("loading database"),new Promise((e,s)=>{if(this.catalog===null||this.catalog.db===null){this.catalog.initialize().then(n=>{this.catalog=n,this.loadDatabase(t,o=>e(o))});return}this.catalog.getAppKeyAsync(this.app,t).then(n=>{let{success:o}=n;if(o===!1)s(null);else{let{val:a}=n;I(a,A(this,p)).then(c=>{w&&console.debug(`DECRYPTED STRING: ${c}`),e(c)}).catch(c=>{s(c)})}})})}),"loadDatabaseAsync");this.saveDatabase=l((t,e,s)=>{w&&console.debug(`in saveDatabase(${t}, ${e}, ${s})`);let n=l(o=>{o==null||typeof o=="object"&&Object.hasOwn(o,"success")&&o&&o.success===!0?s(void 0):s(new Error("Error saving database: "+o)),this.options.closeAfterSave===!0&&A(this,S).call(this)},"saveCallback");if(this.catalog===null||this.catalog.db===null){this.catalog=new h(()=>{this.saveDatabase(t,e,n)});return}R(e,A(this,p)).then(o=>{w&&console.debug(`ENCRYPTED STRING: ${o}`),this.catalog.setAppKeyAsync(this.app,t,o).then(a=>{s(a)}).catch(a=>{s(a)})}).catch(o=>{s(o)})},"saveDatabase");this.deleteDatabase=l((t,e)=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new h(s=>{this.catalog=s,this.deleteDatabase(t,e)});return}this.catalog.getAppKeyAsync(this.app,t).then(s=>{let n=s.id;n!==0&&this.catalog.deleteAppKeyAsync(n).then(o=>{typeof e=="function"&&e(o)}).catch(o=>{typeof e=="function"&&e({success:!1,error:o})})}).catch(s=>{typeof e=="function"&&e({success:!1,error:s})})},"deleteDatabase");this.deleteDatabasePartitions=l(t=>{this.getDatabaseList(e=>{e.forEach(s=>{s.startsWith(t)&&this.deleteDatabase(s)})})},"deleteDatabasePartitions");this.getDatabaseList=l(t=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new h(e=>{this.catalog=e,this.getDatabaseList(t)});return}this.catalog.getAppKeys(this.app,e=>{let s=[];for(let n=0;n<e.length;n++)s.push(e[n].key);typeof t=="function"?t(s):s.forEach(n=>{console.log(n)})})},"getDatabaseList");this.getDatabaseListAsync=l(()=>new Promise((t,e)=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new h(s=>{this.catalog=s,this.getDatabaseListAsync()});return}this.catalog.getAppKeys(this.app,s=>{let n=[];for(let o=0;o<s.length;o++)n.push(s[o].key);t(n)})}),"getDatabaseListAsync");this.getCatalogSummary=l(t=>{if(this.catalog===null||this.catalog.db===null){this.catalog=new h(e=>{this.catalog=e,this.getCatalogSummary(t)});return}this.catalog.getAllKeys(e=>{let s=[],n,o,a,i,c;for(let u=0;u<e.length;u++)n=e[u],a=n.app||"",i=n.key||"",c=n.val||"",o=a.length*2+i.length*2+c.length+1,s.push({app:n.app,key:n.key,size:o});typeof t=="function"?t(s):s.forEach(u=>{console.log(u)})})},"getCatalogSummary");if(w&&console.log("Initialized crypted-indexeddb-adapter"),this.app="sylvie",this.options=t||{},typeof(t==null?void 0:t.appname)!="undefined"&&(this.app=t==null?void 0:t.appname),this.catalog=null,!K(this,P,$).call(this))throw new Error("IndexedDB does not seem to be supported for your environment");t.secret&&D(this,p,t.secret)}usePassword(t){D(this,p,t)}saveDatabaseAsync(t,e){return d(this,null,function*(){return new Promise((s,n)=>{let o=l(a=>{a==null||typeof a=="object"&&Object.hasOwn(a,"success")&&a&&a.success===!0?s(void 0):n(new Error("Error saving database: "+a)),this.options.closeAfterSave===!0&&A(this,S).call(this)},"saveCallback");if(this.catalog===null||this.catalog.db===null){this.catalog=new h(()=>{this.saveDatabase(t,e,o)});return}R(e,A(this,p)).then(a=>{w&&console.debug(`ENCRYPTED STRING: ${a}`),this.catalog.setAppKeyAsync(this.app,t,a).then(i=>{i.success===!0?s(i):n(i)}).catch(i=>{n(i)})}).catch(a=>{n(a)})})})}deleteDatabaseAsync(t){return d(this,null,function*(){return new Promise((e,s)=>{(this.catalog===null||this.catalog.db===null)&&(this.catalog=new h(n=>(this.catalog=n,this.deleteDatabaseAsync(t)))),this.catalog.getAppKeyAsync(this.app,t).then(n=>{let o=n.id;o!==0&&this.catalog.deleteAppKeyAsync(o).then(a=>{a.success===!0?e(a):s(a)}).catch(a=>{s(a)})}).catch(n=>{s(n)})})})}changePassword(t,e){return d(this,null,function*(){return new Promise((s,n)=>{this.loadDatabase(t,o=>{let a=A(this,p);D(this,p,e),this.saveDatabase(t,o,i=>{i&&(D(this,p,a),i.success===!0?s():n(i)),s()})})})})}};l(x,"CryptedIndexedDBAdapter"),p=new WeakMap,S=new WeakMap,P=new WeakSet,$=l(function(){return!!(typeof indexedDB!="undefined"&&indexedDB)},"#checkIDBAvailability");typeof window!="undefined"&&Object.assign(window,{IndexedDBAdapter:x,CryptedIndexedDBAdapter:x});export{x as CryptedIndexedDBAdapter};
//# sourceMappingURL=crypted-indexeddb-adapter.js.map

@@ -7,6 +7,10 @@ /**

export declare class SylvieCatalog {
#private;
db: IDBDatabase;
constructor(callback: (SylvieCatalog: any) => void);
/**
* An alternative to passing a callback to the constructor
*/
initialize(): Promise<SylvieCatalog>;
openCatalog(): IDBOpenDBRequest;
initializeCatalog(): Promise<SylvieCatalog>;
getAppKeyAsync(app: any, key: any): Promise<{

@@ -13,0 +17,0 @@ app: string;

@@ -16,3 +16,3 @@ import Sylvie from "../modules/sylvie";

}) => void): void;
exportDatabase?(dbname: string, dbref: typeof Sylvie, callback?: (result: Error | {
saveDatabase(dbname: string, dbstring: any, callback?: (result: Error | {
success: true;

@@ -23,3 +23,3 @@ } | {

}) => void): void;
saveDatabase(dbname: string, dbstring: any, callback?: (result: Error | {
exportDatabase?(dbname: string, dbref: typeof Sylvie, callback?: (result: Error | {
success: true;

@@ -38,8 +38,8 @@ } | {

}>;
exportDatabaseAsync?(dbname: string, dbref: typeof Sylvie): Promise<{
saveDatabaseAsync(dbname: string, dbstring: string): Promise<{
success: true;
}>;
saveDatabaseAsync(dbname: string, dbstring: string): Promise<{
exportDatabaseAsync?(dbname: string, dbref: typeof Sylvie): Promise<{
success: true;
}>;
}
import { CloneMethods } from "./clone";
export declare function cloneObjectArray(objarray: object[], method: CloneMethods): any;
export declare function cloneObjectArray(objarray: object[], method: CloneMethods): any[];
export type CloneMethods = "parse-stringify" | "shallow" | "shallow-assign" | "shallow-recurse-objects";
export declare function clone(data: object, method: CloneMethods): any;
export declare function clone<T = object>(data: T, method: CloneMethods): T;

@@ -1,3 +0,3 @@

export declare function freeze(obj: object | any): void;
export declare function deepFreeze(obj: object): void;
export declare function unFreeze(obj: object): any;
export declare function freeze<T = object>(obj: T): void;
export declare function deepFreeze<T = object>(obj: T): void;
export declare function unFreeze<T = object>(obj: T): T;

@@ -8,6 +8,5 @@ import esbuild from "esbuild";

"src/sylviejs.ts",
// "src/storage-adapter/incremental-indexeddb-adapter.ts",
// "src/storage-adapter/indexeddb-adapter.ts",
"src/storage-adapter/incremental-indexeddb-adapter.ts",
"src/storage-adapter/crypted-indexeddb-adapter.ts",
// "src/storage-adapter/fs-adapter.ts",
"src/storage-adapter/fs-adapter.ts",
],

@@ -14,0 +13,0 @@ outdir: "dist",

{
"name": "sylviejs",
"version": "0.0.2",
"version": "0.0.3",
"description": "SylvieJS: Fast document oriented javascript in-memory database",

@@ -29,3 +29,5 @@ "homepage": "https://techfort.github.io/LokiJS/",

"typecheck": "tsc --noEmit",
"test:browser": "web-test-runner spec/**/*.ts --node-resolve --playwright --browsers chromium firefox webkit",
"test:browser": "web-test-runner --node-resolve --playwright --browsers chromium firefox webkit",
"test:browser-only": "web-test-runner spec/browser/**/*.ts --node-resolve --playwright --browsers chromium firefox webkit",
"test:node-only": "jest --config jest.config.ts spec/node/*.ts --silent=false",
"test:node": "jest --config jest.config.ts spec/*.ts --silent=false",

@@ -32,0 +34,0 @@ "pretest": "npm run build:only",

@@ -34,2 +34,3 @@ /* eslint-disable @typescript-eslint/no-empty-interface */

interface CryptedIndexedAdapterOptions {
appname: string;
closeAfterSave: boolean;

@@ -52,9 +53,10 @@ secret: string;

*
* @param {string} appname - (Optional) Application name context can be used to distinguish subdomains, 'loki' by default
* @param {CryptedIndexedAdapterOptions} options Configuration options for the adapter
* @param {string} options.appname - (Optional) Application name context can be used to distinguish subdomains, 'sylvie' by default
* @param {boolean} options.closeAfterSave Whether the indexedDB database should be closed after saving.
* @param {boolean} options.secret The password to encrypt with.
*/
export class CryptedIndexedDBAdapter implements PersistenceAdapter {
//, AsyncPersistenceAdapter
export class CryptedIndexedDBAdapter
implements PersistenceAdapter, AsyncPersistenceAdapter
{
isAsync: true;

@@ -67,12 +69,9 @@ app: string;

constructor(
appname: string,
options?: Partial<CryptedIndexedAdapterOptions>
) {
constructor(options?: Partial<CryptedIndexedAdapterOptions>) {
DEBUG && console.log("Initialized crypted-indexeddb-adapter");
this.app = "loki";
this.app = "sylvie";
this.options = options || {};
if (typeof appname !== "undefined") {
this.app = appname;
if (typeof options?.appname !== "undefined") {
this.app = options?.appname;
}

@@ -94,3 +93,16 @@

setSecret(secret: string) {
/**
* Sets a password for use on future load and save of the database.
* Note that this does not re-encrypt the database with the new password. Use changePassword() for that.
* @param secret
* @example
* const db = new Sylvie(TEST_DB_NAME, {
* adapter: new CryptedIndexedDBAdapter();
* });
*
* adapter.usePassword("newpassword");
*
* await newDb.loadDatabaseAsync({});
*/
usePassword(secret: string) {
this.#secret = secret;

@@ -142,2 +154,9 @@ }

});
try {
this.catalog.initialize().then((catalog) => {
this.catalog = catalog;
});
} catch (e) {
console.log(e);
}
return;

@@ -173,2 +192,58 @@ }

/**
* Retrieves a serialized db string from the catalog, returns a promise to a string of the serialized database.
* @param dbname
* @returns {Promise<string>} A promise to a string of the serialized database.
* @example
* const db = new Sylvie(TEST_DB_NAME, {
* adapter: new CryptedIndexedDBAdapter();
* });
* await db.loadDatabaseAsync({});
* // db is now ready to use
* // you can also chain the promises
* await db.loadDatabaseAsync({}).then(() => {
* // db is now ready to use
* });
* // or use async await syntax
* await db.loadDatabaseAsync({});
* // db is now ready to use
* @memberof CryptedIndexedDBAdapter
* @throws {Error} If the database is not found.
* @throws {Error} If the database is not decrypted successfully.
* @throws {Error} If the database is not deserialized successfully.
*/
loadDatabaseAsync = async (dbname: string): Promise<string> => {
DEBUG && console.debug("loading database");
return new Promise((resolve, reject) => {
// lazy open/create db reference so dont -need- callback in constructor
if (this.catalog === null || this.catalog.db === null) {
this.catalog.initialize().then((catalog) => {
this.catalog = catalog;
this.loadDatabase(dbname, (str) => resolve(str));
});
return;
}
// lookup up dbstring in AKV db
this.catalog.getAppKeyAsync(this.app, dbname).then((props) => {
const { success } = props as { success: boolean };
if (success === false) {
reject(null);
} else {
const { val } = props as { val: string };
const encryptedDbString = val;
decryptData(encryptedDbString, this.#secret)
.then((decryptedDbString) => {
DEBUG && console.debug(`DECRYPTED STRING: ${decryptedDbString}`);
resolve(decryptedDbString);
})
.catch((err) => {
reject(err);
});
}
});
});
};
/**
* Saves a serialized db to the catalog.

@@ -244,2 +319,58 @@ *

async saveDatabaseAsync(
dbname: string,
dbstring: string
): Promise<{ success: true }> {
return new Promise((resolve, reject) => {
const saveCallback = (result: { success: boolean } | Error) => {
if (result === null || result === undefined) {
resolve(undefined);
} else if (
typeof result === "object" &&
Object.hasOwn(result, "success") &&
result &&
(result as { success: boolean }).success === true
) {
resolve(undefined);
} else {
reject(new Error("Error saving database: " + result));
}
if (this.options.closeAfterSave === true) {
this.#closeDatabase();
}
};
if (this.catalog === null || this.catalog.db === null) {
this.catalog = new SylvieCatalog(() => {
this.saveDatabase(dbname, dbstring, saveCallback);
});
return;
}
encryptData(dbstring, this.#secret)
.then((encryptedDbString) => {
// lazy open/create db reference so dont -need- callback in constructor
DEBUG && console.debug(`ENCRYPTED STRING: ${encryptedDbString}`);
// set (add/update) entry to AKV database
this.catalog
.setAppKeyAsync(this.app, dbname, encryptedDbString)
.then((res) => {
if (res.success === true) {
resolve(res);
} else {
reject(res);
}
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
});
}
/**

@@ -302,3 +433,73 @@ * Deletes a serialized db from the catalog.

async deleteDatabaseAsync(dbname: string): Promise<{
success: true;
}> {
// lazy open/create db reference and pass callback ahead
return new Promise((resolve, reject) => {
if (this.catalog === null || this.catalog.db === null) {
this.catalog = new SylvieCatalog((catalog) => {
this.catalog = catalog;
return this.deleteDatabaseAsync(dbname);
});
}
// catalog was already initialized, so just lookup object and delete by id
this.catalog
.getAppKeyAsync(this.app, dbname)
.then((result) => {
const id = result.id;
if (id !== 0) {
this.catalog
.deleteAppKeyAsync(id)
.then((res) => {
if (res.success === true) {
resolve(res);
} else {
reject(res);
}
})
.catch((err) => {
reject(err);
});
}
})
.catch((err) => {
reject(err);
});
});
}
/**
* Changes the password of a database and re-encrypts the database with the new password.
* @param {string} dbName The name of the database to change the password of.
* @param {string} newPassword The new password to encrypt the database with.
* @memberof CryptedIndexedDBAdapter
* @returns {Promise<void>} A promise that resolves when the password has been changed.
* @throws {Error} If the adapter is not open.
* @example
* await adapter.changePassword("mydb", "newpassword");
* // The database "mydb" is now encrypted with the password "newpassword".
* // The old password will no longer work.
*/
async changePassword(dbname: string, newPassword: string): Promise<void> {
return new Promise((resolve, reject) => {
this.loadDatabase(dbname, (serializedDbString) => {
const oldPassword = this.#secret;
this.#secret = newPassword;
this.saveDatabase(dbname, serializedDbString, (responseString) => {
if (responseString) {
this.#secret = oldPassword;
if ((responseString as { success: boolean }).success === true) {
resolve();
} else {
reject(responseString);
}
}
resolve();
});
});
});
}
/**
* Removes all database partitions and pages with the base filename passed in.

@@ -305,0 +506,0 @@ * This utility method does not (yet) guarantee async deletions will be completed before returning

@@ -10,14 +10,32 @@ /**

this.db = null;
this.initializeCatalog()
.then((res) => {
if (typeof callback === "function") {
callback(res);
}
})
.catch((err) => {
console.log(err);
throw err;
});
if (callback) {
this.#initializeCatalog()
.then((res) => {
if (typeof callback === "function") {
callback(res);
}
})
.catch((err) => {
console.log(err);
throw err;
});
}
}
/**
* An alternative to passing a callback to the constructor
*/
initialize(): Promise<SylvieCatalog> {
return new Promise((resolve, reject) => {
this.#initializeCatalog()
.then((res) => {
resolve(res);
})
.catch((err) => {
console.log(err);
reject(err);
});
});
}
openCatalog() {

@@ -46,3 +64,3 @@ const openRequest = indexedDB.open("SylvieCatalog", 1);

async initializeCatalog(): Promise<SylvieCatalog> {
async #initializeCatalog(): Promise<SylvieCatalog> {
const cat = this;

@@ -49,0 +67,0 @@ const openRequest = this.openCatalog();

@@ -18,5 +18,5 @@ import Sylvie from "../modules/sylvie";

): void;
exportDatabase?(
saveDatabase(
dbname: string,
dbref: typeof Sylvie,
dbstring: any,
callback?: (

@@ -26,5 +26,5 @@ result: Error | { success: true } | { success: false; error: Error }

): void;
saveDatabase(
exportDatabase?(
dbname: string,
dbstring: any,
dbref: typeof Sylvie,
callback?: (

@@ -41,2 +41,6 @@ result: Error | { success: true } | { success: false; error: Error }

deleteDatabaseAsync(dbname: string): Promise<{ success: true }>;
saveDatabaseAsync(
dbname: string,
dbstring: string
): Promise<{ success: true }>;
exportDatabaseAsync?(

@@ -46,6 +50,2 @@ dbname: string,

): Promise<{ success: true }>;
saveDatabaseAsync(
dbname: string,
dbstring: string
): Promise<{ success: true }>;
}

@@ -13,3 +13,3 @@ /* eslint-disable no-prototype-builtins */

export function clone(data: object, method: CloneMethods) {
export function clone<T = object>(data: T, method: CloneMethods): T {
if (data === null || data === undefined) {

@@ -16,0 +16,0 @@ return null;

/* eslint-disable no-prototype-builtins */
/* eslint-disable no-var */
/**
* LokiJS
* @author Joe Minichino <joe.minichino@gmail.com>
*
* A lightweight document oriented javascript database
*/
"use strict";
import { clone } from "./clone";
export function freeze(obj: object | any) {
export function freeze<T = object>(obj: T): void {
if (!Object.isFrozen(obj)) {

@@ -18,3 +12,3 @@ Object.freeze(obj);

export function deepFreeze(obj: object) {
export function deepFreeze<T = object>(obj: T) {
var prop, i;

@@ -36,3 +30,3 @@ if (Array.isArray(obj)) {

export function unFreeze(obj: object) {
export function unFreeze<T = object>(obj: T) {
if (!Object.isFrozen(obj)) {

@@ -39,0 +33,0 @@ return obj;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc