beanbagdb 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +48 -16
- package/src/system_schema.js +35 -11
- package/test/couchdb.js +76 -19
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -407,7 +407,7 @@ export class BeanBagDB {
|
|
|
407
407
|
throw new DocCreationError(`${v_errors.join(",")}.`)
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
if(input.schema=="
|
|
410
|
+
// if(input.schema=="system_edge"){throw new DocCreationError("This type of record can only be created through the create_edge api")}
|
|
411
411
|
if(Object.keys(input.data).length==0){throw new DocCreationError(`No data provided`)}
|
|
412
412
|
try {
|
|
413
413
|
let doc_obj = await this._insert_pre_checks(input.schema, input.data,input?.meta||{}, input?.settings||{});
|
|
@@ -564,6 +564,10 @@ export class BeanBagDB {
|
|
|
564
564
|
// todo : what if additionalField are allowed ??
|
|
565
565
|
let updated_data = { ...full_doc.data, ...allowed_updates };
|
|
566
566
|
|
|
567
|
+
if(full_doc.schema=="system_edge"){
|
|
568
|
+
// extra checks required. if everything is correct
|
|
569
|
+
updated_data = await this._create_edge(updated_data)
|
|
570
|
+
}
|
|
567
571
|
updated_data = this.util_validate_data({schema:schema.schema,data: updated_data});
|
|
568
572
|
|
|
569
573
|
// primary key check if multiple records can be created
|
|
@@ -622,8 +626,6 @@ export class BeanBagDB {
|
|
|
622
626
|
}
|
|
623
627
|
|
|
624
628
|
|
|
625
|
-
|
|
626
|
-
|
|
627
629
|
/**
|
|
628
630
|
* Deletes a document from the database by its ID.
|
|
629
631
|
*
|
|
@@ -721,6 +723,21 @@ export class BeanBagDB {
|
|
|
721
723
|
return schemas
|
|
722
724
|
}
|
|
723
725
|
|
|
726
|
+
},
|
|
727
|
+
schema_icons: async (criteria)=>{
|
|
728
|
+
let schemaSearch = await this.db_api.search({
|
|
729
|
+
selector: { schema: "schema" },
|
|
730
|
+
});
|
|
731
|
+
// console.log(schemaSearch)
|
|
732
|
+
if (schemaSearch.docs.length == 0) {
|
|
733
|
+
throw new DocNotFoundError(BeanBagDB.error_codes.schema_not_found);
|
|
734
|
+
}else{
|
|
735
|
+
let schemas = {}
|
|
736
|
+
schemaSearch.docs.map(doc=>{
|
|
737
|
+
schemas[doc.data.name] = doc.data.settings.svg_icon25||""
|
|
738
|
+
})
|
|
739
|
+
return schemas
|
|
740
|
+
}
|
|
724
741
|
}
|
|
725
742
|
}
|
|
726
743
|
if(!input.type){throw new ValidationError("No type provided. Must be: "+Object.keys(fetch_docs).join(","))}
|
|
@@ -821,21 +838,31 @@ export class BeanBagDB {
|
|
|
821
838
|
* @param {object} node1
|
|
822
839
|
* @param {object} node2
|
|
823
840
|
* @param {string} edge_name
|
|
824
|
-
* @param {
|
|
841
|
+
* @param {string} note
|
|
825
842
|
* @returns {Object}
|
|
826
843
|
*/
|
|
827
|
-
async
|
|
828
|
-
|
|
844
|
+
async _create_edge(input){
|
|
845
|
+
console.log(input)
|
|
846
|
+
let {node1,node2,edge_name,note=""} = input
|
|
829
847
|
this._check_ready_to_use();
|
|
830
848
|
if(!edge_name){throw new ValidationError("edge_name required")}
|
|
831
|
-
if(Object.keys(node1)==0){throw new ValidationError("node1 required")}
|
|
832
|
-
if(Object.keys(node2)==0){throw new ValidationError("node2 required")}
|
|
833
|
-
|
|
849
|
+
if(!node1|| Object.keys(node1).length==0){throw new ValidationError("node1 required")}
|
|
850
|
+
if(!node2|| Object.keys(node2).length==0){throw new ValidationError("node2 required")}
|
|
851
|
+
// if nodes are of type string, they are assumed to be ids since they are stored in the DB as ids
|
|
852
|
+
if(typeof(node1)=="string"){node1 = {_id:node1}}
|
|
853
|
+
if(typeof(node2)=="string"){node2 = {_id:node2}}
|
|
834
854
|
let n1 = await this.read(node1)
|
|
835
855
|
let n2 = await this.read(node2)
|
|
856
|
+
if(n1.doc._id==n2.doc._id){
|
|
857
|
+
throw new ValidationError("Both nodes cannot be the same")
|
|
858
|
+
}
|
|
859
|
+
if(n1.doc.schema=="system_edge"|| n2.doc.schema=="system_edge"){
|
|
860
|
+
throw new ValidationError("A node cannot be an existing edge document")
|
|
861
|
+
}
|
|
836
862
|
let edges_constraint
|
|
837
863
|
|
|
838
864
|
try {
|
|
865
|
+
// check if edge_name has a related edge_constraint
|
|
839
866
|
let d = await this.read({schema:"system_edge_constraint",data:{name:edge_name}})
|
|
840
867
|
edges_constraint = d["doc"]["data"]
|
|
841
868
|
let errors = []
|
|
@@ -850,7 +877,7 @@ async create_edge(input){
|
|
|
850
877
|
node2id = n1.doc._id
|
|
851
878
|
}
|
|
852
879
|
}else{
|
|
853
|
-
|
|
880
|
+
errors.push("Invalid nodes.This config of nodes not allowed")
|
|
854
881
|
}
|
|
855
882
|
|
|
856
883
|
let records = await this.search({selector:{schema:"system_edge","data.edge_name":edge_name}})
|
|
@@ -870,18 +897,17 @@ async create_edge(input){
|
|
|
870
897
|
}
|
|
871
898
|
|
|
872
899
|
if(errors.length==0){
|
|
873
|
-
let edge = await this.create({schema:"system_edge",data:
|
|
874
|
-
return
|
|
900
|
+
// let edge = await this.create({schema:"system_edge",data:})
|
|
901
|
+
return {node1: node1id , node2: node2id ,edge_name:edge_name ,note:note}
|
|
875
902
|
}else{
|
|
876
903
|
throw new RelationError(errors)
|
|
877
904
|
}
|
|
878
905
|
|
|
879
906
|
} catch (error) {
|
|
880
907
|
if(error instanceof DocNotFoundError){
|
|
881
|
-
let doc = {node1:"*",node2:"*",name:edge_name,
|
|
908
|
+
let doc = {node1:"*",node2:"*",name:edge_name,note:note}
|
|
882
909
|
let new_doc = await this.create({schema:"system_edge_constraint",data:doc})
|
|
883
|
-
|
|
884
|
-
return edge
|
|
910
|
+
return {node1: n1.doc._id,node2: n2.doc._id,edge_name:edge_name ,note:note}
|
|
885
911
|
}else{
|
|
886
912
|
throw error
|
|
887
913
|
}
|
|
@@ -1142,7 +1168,10 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
|
|
|
1142
1168
|
// validate data
|
|
1143
1169
|
if(!schemaDoc.active){throw new DocCreationError(`The schema "${schema}" is not active`)}
|
|
1144
1170
|
|
|
1145
|
-
let new_data
|
|
1171
|
+
let new_data
|
|
1172
|
+
if(schema!="system_edge"){
|
|
1173
|
+
new_data = this.util_validate_data({schema:schemaDoc.schema, data});
|
|
1174
|
+
}
|
|
1146
1175
|
|
|
1147
1176
|
// validate meta
|
|
1148
1177
|
if(Object.keys(meta).length>0){
|
|
@@ -1161,6 +1190,9 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
|
|
|
1161
1190
|
if (schema == "schema") {
|
|
1162
1191
|
//more checks are required
|
|
1163
1192
|
this.util_validate_schema_object(new_data);
|
|
1193
|
+
}else if(schema == "system_edge"){
|
|
1194
|
+
let create_edge_after_checks = await this._create_edge(data)
|
|
1195
|
+
new_data = create_edge_after_checks
|
|
1164
1196
|
}
|
|
1165
1197
|
// @TODO : check if single record setting is set to true
|
|
1166
1198
|
//console.log(schemaDoc)
|
package/src/system_schema.js
CHANGED
|
@@ -11,7 +11,7 @@ export const default_app = {
|
|
|
11
11
|
active: true,
|
|
12
12
|
description: "Meta-schema or the schema for defining other schemas",
|
|
13
13
|
system_generated: true,
|
|
14
|
-
version:
|
|
14
|
+
version: 1,
|
|
15
15
|
title: "Schema document",
|
|
16
16
|
schema: {
|
|
17
17
|
type: "object",
|
|
@@ -127,6 +127,13 @@ export const default_app = {
|
|
|
127
127
|
description:
|
|
128
128
|
"Describes how this schema was installed in database. This is determined by the system. By default the value is human. Possible value: name of the app , where it was cloned from etc...",
|
|
129
129
|
},
|
|
130
|
+
svg_icon25: {
|
|
131
|
+
type: "string",
|
|
132
|
+
title: "SVG Icon for schema",
|
|
133
|
+
default: "human",
|
|
134
|
+
description:
|
|
135
|
+
"The height and width should be 25px",
|
|
136
|
+
}
|
|
130
137
|
},
|
|
131
138
|
required: [
|
|
132
139
|
"primary_keys",
|
|
@@ -142,11 +149,12 @@ export const default_app = {
|
|
|
142
149
|
non_editable_fields: ["system_generated"],
|
|
143
150
|
encrypted_fields: [],
|
|
144
151
|
display_fields: ["name", "version", "description", "title", "active"],
|
|
152
|
+
svg_icon25:"<svg xmlns='http://www.w3.org/2000/svg' width='25' height='16' fill='currentColor' class='bi bi-database-fill-gear' viewBox='0 0 16 16'><path d='M8 1c-1.573 0-3.022.289-4.096.777C2.875 2.245 2 2.993 2 4s.875 1.755 1.904 2.223C4.978 6.711 6.427 7 8 7s3.022-.289 4.096-.777C13.125 5.755 14 5.007 14 4s-.875-1.755-1.904-2.223C11.022 1.289 9.573 1 8 1'/><path d='M2 7v-.839c.457.432 1.004.751 1.49.972C4.722 7.693 6.318 8 8 8s3.278-.307 4.51-.867c.486-.22 1.033-.54 1.49-.972V7c0 .424-.155.802-.411 1.133a4.51 4.51 0 0 0-4.815 1.843A12 12 0 0 1 8 10c-1.573 0-3.022-.289-4.096-.777C2.875 8.755 2 8.007 2 7m6.257 3.998L8 11c-1.682 0-3.278-.307-4.51-.867-.486-.22-1.033-.54-1.49-.972V10c0 1.007.875 1.755 1.904 2.223C4.978 12.711 6.427 13 8 13h.027a4.55 4.55 0 0 1 .23-2.002m-.002 3L8 14c-1.682 0-3.278-.307-4.51-.867-.486-.22-1.033-.54-1.49-.972V13c0 1.007.875 1.755 1.904 2.223C4.978 15.711 6.427 16 8 16c.536 0 1.058-.034 1.555-.097a4.5 4.5 0 0 1-1.3-1.905m3.631-4.538c.18-.613 1.048-.613 1.229 0l.043.148a.64.64 0 0 0 .921.382l.136-.074c.561-.306 1.175.308.87.869l-.075.136a.64.64 0 0 0 .382.92l.149.045c.612.18.612 1.048 0 1.229l-.15.043a.64.64 0 0 0-.38.921l.074.136c.305.561-.309 1.175-.87.87l-.136-.075a.64.64 0 0 0-.92.382l-.045.149c-.18.612-1.048.612-1.229 0l-.043-.15a.64.64 0 0 0-.921-.38l-.136.074c-.561.305-1.175-.309-.87-.87l.075-.136a.64.64 0 0 0-.382-.92l-.148-.045c-.613-.18-.613-1.048 0-1.229l.148-.043a.64.64 0 0 0 .382-.921l-.074-.136c-.306-.561.308-1.175.869-.87l.136.075a.64.64 0 0 0 .92-.382zM14 12.5a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0'/></svg>"
|
|
145
153
|
},
|
|
146
154
|
},
|
|
147
155
|
{
|
|
148
156
|
system_generated: true,
|
|
149
|
-
version:
|
|
157
|
+
version: 1,
|
|
150
158
|
description:
|
|
151
159
|
"To store user defined key. this can include anything like API tokens etc. There is a special method to fetch this. The values are encrypted",
|
|
152
160
|
name: "system_key",
|
|
@@ -181,10 +189,11 @@ export const default_app = {
|
|
|
181
189
|
primary_keys: ["name"],
|
|
182
190
|
encrypted_fields: ["value"],
|
|
183
191
|
non_editable_fields: [],
|
|
192
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-key-fill" viewBox="0 0 16 16"><path d="M3.5 11.5a3.5 3.5 0 1 1 3.163-5H14L15.5 8 14 9.5l-1-1-1 1-1-1-1 1-1-1-1 1H6.663a3.5 3.5 0 0 1-3.163 2M2.5 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/></svg>`
|
|
184
193
|
},
|
|
185
194
|
},
|
|
186
195
|
{
|
|
187
|
-
version:
|
|
196
|
+
version: 1,
|
|
188
197
|
system_generated: true,
|
|
189
198
|
description:
|
|
190
199
|
"The system relies on these settings for proper functioning or enabling optional features.",
|
|
@@ -211,6 +220,7 @@ export const default_app = {
|
|
|
211
220
|
primary_keys: ["name"],
|
|
212
221
|
non_editable_fields: ["name"],
|
|
213
222
|
encrypted_fields: [],
|
|
223
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-gear-fill" viewBox="0 0 16 16"><path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/></svg>`
|
|
214
224
|
},
|
|
215
225
|
},
|
|
216
226
|
{
|
|
@@ -218,7 +228,7 @@ export const default_app = {
|
|
|
218
228
|
title: "Edge constraint",
|
|
219
229
|
system_generated: true,
|
|
220
230
|
active: true,
|
|
221
|
-
version:
|
|
231
|
+
version: 1,
|
|
222
232
|
description:
|
|
223
233
|
"To define edge constraints for simple directed graph of records.",
|
|
224
234
|
schema: {
|
|
@@ -268,6 +278,7 @@ export const default_app = {
|
|
|
268
278
|
primary_keys: ["name"],
|
|
269
279
|
non_editable_fields: ["name"],
|
|
270
280
|
encrypted_fields: [],
|
|
281
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-node-plus-fill" viewBox="0 0 16 16"><path d="M11 13a5 5 0 1 0-4.975-5.5H4A1.5 1.5 0 0 0 2.5 6h-1A1.5 1.5 0 0 0 0 7.5v1A1.5 1.5 0 0 0 1.5 10h1A1.5 1.5 0 0 0 4 8.5h2.025A5 5 0 0 0 11 13m.5-7.5v2h2a.5.5 0 0 1 0 1h-2v2a.5.5 0 0 1-1 0v-2h-2a.5.5 0 0 1 0-1h2v-2a.5.5 0 0 1 1 0"/></svg>`
|
|
271
282
|
},
|
|
272
283
|
},
|
|
273
284
|
{
|
|
@@ -275,12 +286,12 @@ export const default_app = {
|
|
|
275
286
|
title: "Edge in the system graph",
|
|
276
287
|
active: true,
|
|
277
288
|
system_generated: true,
|
|
278
|
-
version:
|
|
289
|
+
version: 1,
|
|
279
290
|
description: "To define edges in the simple directed graph of records.",
|
|
280
291
|
schema: {
|
|
281
292
|
type: "object",
|
|
282
293
|
additionalProperties: true,
|
|
283
|
-
required: ["node1", "node2", "
|
|
294
|
+
required: ["node1", "node2", "edge_name"],
|
|
284
295
|
properties: {
|
|
285
296
|
node1: {
|
|
286
297
|
type: "string",
|
|
@@ -291,12 +302,17 @@ export const default_app = {
|
|
|
291
302
|
edge_name: {
|
|
292
303
|
type: "string",
|
|
293
304
|
},
|
|
305
|
+
note:{
|
|
306
|
+
type:"string",
|
|
307
|
+
default:" "
|
|
308
|
+
}
|
|
294
309
|
},
|
|
295
310
|
},
|
|
296
311
|
settings: {
|
|
297
|
-
primary_keys: ["node1", "node2", "
|
|
312
|
+
primary_keys: ["node1", "node2", "edge_name"],
|
|
298
313
|
non_editable_fields: ["edge_type"],
|
|
299
314
|
encrypted_fields: [],
|
|
315
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-diagram-2-fill" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H11a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 5 7h2.5V6A1.5 1.5 0 0 1 6 4.5zm-3 8A1.5 1.5 0 0 1 4.5 10h1A1.5 1.5 0 0 1 7 11.5v1A1.5 1.5 0 0 1 5.5 14h-1A1.5 1.5 0 0 1 3 12.5zm6 0a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1A1.5 1.5 0 0 1 9 12.5z"/></svg>`
|
|
300
316
|
},
|
|
301
317
|
},
|
|
302
318
|
{
|
|
@@ -304,7 +320,7 @@ export const default_app = {
|
|
|
304
320
|
title: "Media content",
|
|
305
321
|
active: true,
|
|
306
322
|
system_generated: true,
|
|
307
|
-
version:
|
|
323
|
+
version: 1,
|
|
308
324
|
description: "To store images as Base64",
|
|
309
325
|
schema: {
|
|
310
326
|
type: "object",
|
|
@@ -329,6 +345,7 @@ export const default_app = {
|
|
|
329
345
|
primary_keys: ["caption"],
|
|
330
346
|
non_editable_fields: [],
|
|
331
347
|
encrypted_fields: [],
|
|
348
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-file-image" viewBox="0 0 16 16"><path d="M8.002 5.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/><path d="M12 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2M3 2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v8l-2.083-2.083a.5.5 0 0 0-.76.063L8 11 5.835 9.7a.5.5 0 0 0-.611.076L3 12z"/></svg>`
|
|
332
349
|
},
|
|
333
350
|
},
|
|
334
351
|
{
|
|
@@ -336,7 +353,7 @@ export const default_app = {
|
|
|
336
353
|
system_generated: true,
|
|
337
354
|
title: "System log",
|
|
338
355
|
active: true,
|
|
339
|
-
version:
|
|
356
|
+
version: 1,
|
|
340
357
|
description: "To define edges in the simple directed graph of records.",
|
|
341
358
|
schema: {
|
|
342
359
|
type: "object",
|
|
@@ -362,6 +379,7 @@ export const default_app = {
|
|
|
362
379
|
primary_keys: [],
|
|
363
380
|
non_editable_fields: [],
|
|
364
381
|
encrypted_fields: [],
|
|
382
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-clock-history" viewBox="0 0 16 16"><path d="M8.515 1.019A7 7 0 0 0 8 1V0a8 8 0 0 1 .589.022zm2.004.45a7 7 0 0 0-.985-.299l.219-.976q.576.129 1.126.342zm1.37.71a7 7 0 0 0-.439-.27l.493-.87a8 8 0 0 1 .979.654l-.615.789a7 7 0 0 0-.418-.302zm1.834 1.79a7 7 0 0 0-.653-.796l.724-.69q.406.429.747.91zm.744 1.352a7 7 0 0 0-.214-.468l.893-.45a8 8 0 0 1 .45 1.088l-.95.313a7 7 0 0 0-.179-.483m.53 2.507a7 7 0 0 0-.1-1.025l.985-.17q.1.58.116 1.17zm-.131 1.538q.05-.254.081-.51l.993.123a8 8 0 0 1-.23 1.155l-.964-.267q.069-.247.12-.501m-.952 2.379q.276-.436.486-.908l.914.405q-.24.54-.555 1.038zm-.964 1.205q.183-.183.35-.378l.758.653a8 8 0 0 1-.401.432z"/><path d="M8 1a7 7 0 1 0 4.95 11.95l.707.707A8.001 8.001 0 1 1 8 0z"/><path d="M7.5 3a.5.5 0 0 1 .5.5v5.21l3.248 1.856a.5.5 0 0 1-.496.868l-3.5-2A.5.5 0 0 1 7 9V3.5a.5.5 0 0 1 .5-.5"/></svg>`
|
|
365
383
|
},
|
|
366
384
|
},
|
|
367
385
|
{
|
|
@@ -369,7 +387,7 @@ export const default_app = {
|
|
|
369
387
|
system_generated: true,
|
|
370
388
|
title: "Executable script",
|
|
371
389
|
active: true,
|
|
372
|
-
version:
|
|
390
|
+
version: 1,
|
|
373
391
|
description: "To create scripts that implement some logic. Can run both on browser and client.",
|
|
374
392
|
schema: {
|
|
375
393
|
type: "object",
|
|
@@ -409,6 +427,7 @@ export const default_app = {
|
|
|
409
427
|
primary_keys: ["name"],
|
|
410
428
|
non_editable_fields: [],
|
|
411
429
|
encrypted_fields: [],
|
|
430
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-braces-asterisk" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.114 8.063V7.9c1.005-.102 1.497-.615 1.497-1.6V4.503c0-1.094.39-1.538 1.354-1.538h.273V2h-.376C2.25 2 1.49 2.759 1.49 4.352v1.524c0 1.094-.376 1.456-1.49 1.456v1.299c1.114 0 1.49.362 1.49 1.456v1.524c0 1.593.759 2.352 2.372 2.352h.376v-.964h-.273c-.964 0-1.354-.444-1.354-1.538V9.663c0-.984-.492-1.497-1.497-1.6M14.886 7.9v.164c-1.005.103-1.497.616-1.497 1.6v1.798c0 1.094-.39 1.538-1.354 1.538h-.273v.964h.376c1.613 0 2.372-.759 2.372-2.352v-1.524c0-1.094.376-1.456 1.49-1.456v-1.3c-1.114 0-1.49-.362-1.49-1.456V4.352C14.51 2.759 13.75 2 12.138 2h-.376v.964h.273c.964 0 1.354.444 1.354 1.538V6.3c0 .984.492 1.497 1.497 1.6M7.5 11.5V9.207l-1.621 1.621-.707-.707L6.792 8.5H4.5v-1h2.293L5.172 5.879l.707-.707L7.5 6.792V4.5h1v2.293l1.621-1.621.707.707L9.208 7.5H11.5v1H9.207l1.621 1.621-.707.707L8.5 9.208V11.5z"/></svg>`
|
|
412
431
|
},
|
|
413
432
|
},
|
|
414
433
|
],
|
|
@@ -464,7 +483,12 @@ export const app_data_schema = {
|
|
|
464
483
|
default_setting:{
|
|
465
484
|
type: "object",
|
|
466
485
|
additionalProperties:true,
|
|
467
|
-
default : {
|
|
486
|
+
default : {
|
|
487
|
+
primary_keys: [],
|
|
488
|
+
non_editable_fields: [],
|
|
489
|
+
encrypted_fields: [],
|
|
490
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-file-earmark" viewBox="0 0 16 16"><path d="M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5z"/></svg>`
|
|
491
|
+
}
|
|
468
492
|
}
|
|
469
493
|
},
|
|
470
494
|
};
|
package/test/couchdb.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import {BeanBagDB} from '../src/index.js';
|
|
2
|
+
import crypto from 'crypto'
|
|
2
3
|
// const SDB = require("beanbagdb")
|
|
3
4
|
|
|
4
5
|
import Ajv from 'ajv';
|
|
5
6
|
import nano from "nano";
|
|
6
|
-
import BeanBagDB from '../src/index.js';
|
|
7
7
|
|
|
8
8
|
export class BeanBagDB_CouchDB extends BeanBagDB {
|
|
9
9
|
constructor(db_url,db_name,encryption_key){
|
|
@@ -41,30 +41,87 @@ export class BeanBagDB_CouchDB extends BeanBagDB {
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
utils:{
|
|
44
|
-
encrypt: async
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
encrypt: async (text, encryptionKey) => {
|
|
45
|
+
const encoder = new TextEncoder();
|
|
46
|
+
const data = encoder.encode(text); // Encode the text into bytes
|
|
47
|
+
|
|
48
|
+
// Ensure the encryption key is of valid length (16, 24, or 32 bytes for AES-GCM)
|
|
49
|
+
const keyBytes = encoder.encode(encryptionKey);
|
|
50
|
+
if (
|
|
51
|
+
keyBytes.length !== 16 &&
|
|
52
|
+
keyBytes.length !== 24 &&
|
|
53
|
+
keyBytes.length !== 32
|
|
54
|
+
) {
|
|
55
|
+
throw new Error("Encryption key must be 16, 24, or 32 bytes long.");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Convert encryptionKey to CryptoKey
|
|
59
|
+
const key = await crypto.subtle.importKey(
|
|
60
|
+
"raw",
|
|
61
|
+
keyBytes,
|
|
62
|
+
{ name: "AES-GCM" },
|
|
63
|
+
false,
|
|
64
|
+
["encrypt"]
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Create a random initialization vector (IV)
|
|
68
|
+
const iv = crypto.getRandomValues(new Uint8Array(12)); // 12 bytes for AES-GCM
|
|
69
|
+
|
|
70
|
+
// Encrypt the data
|
|
71
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
72
|
+
{ name: "AES-GCM", iv: iv },
|
|
73
|
+
key,
|
|
74
|
+
data
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Convert encrypted data and IV to base64 for storage
|
|
78
|
+
const encryptedArray = new Uint8Array(encrypted);
|
|
79
|
+
const encryptedText = btoa(String.fromCharCode(...encryptedArray));
|
|
80
|
+
const ivText = btoa(String.fromCharCode(...iv));
|
|
81
|
+
|
|
82
|
+
return ivText + ":" + encryptedText; // Store IV and encrypted text together
|
|
51
83
|
},
|
|
52
|
-
decrypt
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
84
|
+
decrypt: async (encryptedText, encryptionKey) => {
|
|
85
|
+
const [ivText, encryptedData] = encryptedText.split(":");
|
|
86
|
+
|
|
87
|
+
// Convert IV and encrypted data from base64 to byte arrays
|
|
88
|
+
const iv = Uint8Array.from(atob(ivText), (c) => c.charCodeAt(0));
|
|
89
|
+
const encryptedArray = Uint8Array.from(atob(encryptedData), (c) =>
|
|
90
|
+
c.charCodeAt(0)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const encoder = new TextEncoder();
|
|
94
|
+
|
|
95
|
+
// Convert encryptionKey to CryptoKey
|
|
96
|
+
const key = await crypto.subtle.importKey(
|
|
97
|
+
"raw",
|
|
98
|
+
encoder.encode(encryptionKey),
|
|
99
|
+
{ name: "AES-GCM" },
|
|
100
|
+
false,
|
|
101
|
+
["decrypt"]
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Decrypt the data
|
|
105
|
+
const decrypted = await crypto.subtle.decrypt(
|
|
106
|
+
{ name: "AES-GCM", iv: iv },
|
|
107
|
+
key,
|
|
108
|
+
encryptedArray
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Convert decrypted data back to a string
|
|
112
|
+
const decoder = new TextDecoder();
|
|
113
|
+
return decoder.decode(decrypted);
|
|
59
114
|
},
|
|
60
115
|
ping : ()=>{
|
|
61
116
|
// @TODO ping the database to check connectivity when class is ready to use
|
|
62
117
|
},
|
|
63
118
|
validate_schema: (schema_obj, data_obj)=>{
|
|
64
|
-
const ajv = new Ajv({code: {esm: true}}) // options can be passed, e.g. {allErrors: true}
|
|
119
|
+
const ajv = new Ajv({code: {esm: true},strict:false,useDefaults:true}) // options can be passed, e.g. {allErrors: true}
|
|
120
|
+
const data_copy = {...data_obj}
|
|
65
121
|
const validate = ajv.compile(schema_obj);
|
|
66
|
-
const valid = validate(
|
|
67
|
-
|
|
122
|
+
const valid = validate(data_copy);
|
|
123
|
+
|
|
124
|
+
return {valid,validate,data:data_copy}
|
|
68
125
|
}
|
|
69
126
|
}
|
|
70
127
|
}
|