@bbn/bbn 2.0.221 → 2.0.222

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/dist/com.js CHANGED
@@ -53,7 +53,6 @@ const fetchRequest = (method, url, config = {}, aborter) => {
53
53
  const hasBody = methodsWithBody.includes(method.toUpperCase());
54
54
  if (config.data != null && hasBody) {
55
55
  // You can get fancier here (JSON, FormData, etc.)
56
- bbn.fn.log('DATA', config.data);
57
56
  if (typeof config.data === 'object' && !(config.data instanceof FormData)) {
58
57
  fetchConfig.headers.set('Content-Type', 'application/json');
59
58
  fetchConfig.body = JSON.stringify(config.data);
package/dist/db.d.ts CHANGED
@@ -16,6 +16,7 @@ type WhereObject = Record<string, unknown> | null;
16
16
  type OrderClause = unknown;
17
17
  interface IDbApi {
18
18
  lastError(): unknown;
19
+ close(): void;
19
20
  insert(table: string, data: Record<string, unknown> | Record<string, unknown>[]): Promise<number>;
20
21
  update(table: string, data: Record<string, unknown>, where: WhereObject, replace?: boolean): Promise<number>;
21
22
  delete(table: string, where: Record<string, unknown>): Promise<number>;
@@ -32,7 +33,8 @@ interface DbManager {
32
33
  _stores: Record<string, unknown>;
33
34
  ok: boolean;
34
35
  open(name: string): Promise<IDbApi>;
35
- add(database: string, name: string, structure: DbStructure): Promise<void>;
36
+ add(database: string, name: string, structure: DbStructure): Promise<IDBDatabase>;
37
+ openRaw(name: string, version?: number): Promise<IDBDatabase>;
36
38
  remove(database: string, name: string): Promise<void>;
37
39
  updateStructure(storeName: string, structure: DbStructure, database: IDBDatabase): void;
38
40
  reopenWithUpgrade(name: string): Promise<IDBDatabase>;
package/dist/db.js CHANGED
@@ -82,12 +82,22 @@ class DbObject {
82
82
  this.lastErr = null;
83
83
  this.dbName = dbName;
84
84
  }
85
- get connection() {
86
- const conn = db._connections[this.dbName];
87
- if (!conn) {
88
- throw new Error(_('The database %s is not open', this.dbName));
89
- }
90
- return conn;
85
+ hasMissingStores(database, conn) {
86
+ const structures = db._structures[database] || {};
87
+ return Object.keys(structures).some(storeName => !conn.objectStoreNames.contains(storeName));
88
+ }
89
+ getConnection() {
90
+ return __awaiter(this, arguments, void 0, function* (database = '') {
91
+ let conn = db._connections[database || this.dbName];
92
+ if (!conn) {
93
+ const tmp = yield db.open(database || this.dbName);
94
+ if (!db._connections[database || this.dbName]) {
95
+ throw new Error(_('The database %s is not open', this.dbName));
96
+ }
97
+ conn = db._connections[database || this.dbName];
98
+ }
99
+ return conn;
100
+ });
91
101
  }
92
102
  get structure() {
93
103
  const structure = db._structures[this.dbName];
@@ -97,27 +107,43 @@ class DbObject {
97
107
  return structure;
98
108
  }
99
109
  getStore(table, mode) {
100
- const tx = this.connection.transaction([table], mode);
101
- tx.onabort = () => {
102
- this.lastErr = tx.error;
103
- log(tx.error);
104
- };
105
- tx.onerror = () => {
106
- this.lastErr = tx.error;
107
- log(tx.error);
108
- };
109
- return [tx, tx.objectStore(table)];
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ const connection = yield this.getConnection();
112
+ if (!this.structure[table]) {
113
+ throw new Error(_('Table %s is not defined in database structure %s', table, this.dbName));
114
+ }
115
+ if (!connection.objectStoreNames.contains(table)) {
116
+ throw new Error(_('Table %s does not exist in database %s. Schema upgrade required.', table, this.dbName));
117
+ }
118
+ const tx = connection.transaction([table], mode);
119
+ tx.onabort = () => {
120
+ this.lastErr = tx.error;
121
+ log(tx.error);
122
+ };
123
+ tx.onerror = () => {
124
+ this.lastErr = tx.error;
125
+ log(tx.error);
126
+ };
127
+ return [tx, tx.objectStore(table)];
128
+ });
110
129
  }
111
130
  lastError() {
112
131
  return this.lastErr;
113
132
  }
133
+ close() {
134
+ const conn = db._connections[this.dbName];
135
+ if (conn) {
136
+ conn.close();
137
+ delete db._connections[this.dbName];
138
+ }
139
+ }
114
140
  insert(table, data) {
115
141
  return __awaiter(this, void 0, void 0, function* () {
116
142
  const rows = Array.isArray(data) ? data : [data];
117
143
  if (!rows.length) {
118
144
  return 0;
119
145
  }
120
- const [tx, store] = this.getStore(table, 'readwrite');
146
+ const [tx, store] = yield this.getStore(table, 'readwrite');
121
147
  let inserted = 0;
122
148
  for (const row of rows) {
123
149
  const req = store.put(row);
@@ -144,7 +170,7 @@ class DbObject {
144
170
  if (Array.isArray(primary)) {
145
171
  throw new Error(_('Composite primary keys are not supported by this update implementation'));
146
172
  }
147
- const [tx, store] = this.getStore(table, 'readwrite');
173
+ const [tx, store] = yield this.getStore(table, 'readwrite');
148
174
  let updated = 0;
149
175
  for (const row of rows) {
150
176
  const nextRow = extend({}, replace ? { [primary]: row[primary] } : row, data);
@@ -174,7 +200,7 @@ class DbObject {
174
200
  if (!(primary in where)) {
175
201
  throw new Error(_('No primary key in the filter'));
176
202
  }
177
- const [tx, store] = this.getStore(table, 'readwrite');
203
+ const [tx, store] = yield this.getStore(table, 'readwrite');
178
204
  store.delete(where[primary]);
179
205
  yield transactionDone(tx);
180
206
  return 1;
@@ -196,7 +222,7 @@ class DbObject {
196
222
  selectAll(table_1) {
197
223
  return __awaiter(this, arguments, void 0, function* (table, fields = [], where = null, order = null, start = 0, limit = null) {
198
224
  void order;
199
- const [tx, store] = this.getStore(table, 'readonly');
225
+ const [tx, store] = yield this.getStore(table, 'readonly');
200
226
  const structure = this.structure[table];
201
227
  const primary = getPrimaryKey(structure);
202
228
  const results = [];
@@ -241,7 +267,7 @@ class DbObject {
241
267
  }
242
268
  const matches = !where || !((_b = (_a = globalThis.bbn) === null || _a === void 0 ? void 0 : _a.fn) === null || _b === void 0 ? void 0 : _b.search)
243
269
  ? true
244
- : !globalThis.bbn.fn.search([cursor.value], where);
270
+ : 0 === globalThis.bbn.fn.search([cursor.value], where);
245
271
  if (matches) {
246
272
  if (i >= start) {
247
273
  const transformed = transformResult(cursor.value, fields);
@@ -277,11 +303,15 @@ class DbObject {
277
303
  }
278
304
  copyTable(target_1, table_1) {
279
305
  return __awaiter(this, arguments, void 0, function* (target, table, fields = [], where = null, order = null, start = 0, limit = null) {
280
- if (!this.connection.objectStoreNames.contains(target)) {
306
+ if (!this.structure[table]) {
307
+ throw new Error(_('Source table %s does not exist in structure', table));
308
+ }
309
+ let connection = yield this.getConnection();
310
+ if (!connection.objectStoreNames.contains(target)) {
281
311
  yield db.add(this.dbName, target, this.structure[table]);
282
- yield db.open(this.dbName);
312
+ connection = yield this.getConnection();
283
313
  }
284
- if (!this.connection.objectStoreNames.contains(target)) {
314
+ if (!connection.objectStoreNames.contains(target)) {
285
315
  throw new Error(_('The target table %s does not exist', target));
286
316
  }
287
317
  const rows = yield this.selectAll(table, fields, where, order, start, limit);
@@ -348,8 +378,12 @@ const db = {
348
378
  },
349
379
  reopenWithUpgrade(name) {
350
380
  return __awaiter(this, void 0, void 0, function* () {
381
+ if (!this._structures[name]) {
382
+ throw new Error(_('Impossible to find a structure for the database %s', name));
383
+ }
351
384
  const existingVersion = yield this.getExistingVersion(name);
352
385
  const nextVersion = existingVersion + 1;
386
+ log(_('Going from version %s to version %s for database %s', existingVersion, nextVersion, name));
353
387
  if (this._connections[name]) {
354
388
  this._connections[name].close();
355
389
  delete this._connections[name];
@@ -374,7 +408,10 @@ const db = {
374
408
  resolve(req.result);
375
409
  };
376
410
  req.onerror = () => reject(req.error);
377
- req.onblocked = () => reject(req.error || new Error(_('IndexedDB upgrade blocked')));
411
+ req.onblocked = (event) => {
412
+ log(event);
413
+ reject(_('reopenWithUpgrade: Upgrade blocked for database %s. Please close other connections to proceed.', name));
414
+ };
378
415
  });
379
416
  });
380
417
  },
@@ -405,6 +442,9 @@ const db = {
405
442
  resolve(req.result);
406
443
  };
407
444
  req.onerror = () => reject(req.error);
445
+ req.onblocked = (event) => {
446
+ reject(_('open: Upgrade blocked for database %s. Please close other connections to proceed.', database));
447
+ };
408
448
  });
409
449
  return new DbObject(database);
410
450
  });
@@ -412,6 +452,7 @@ const db = {
412
452
  add(database, name, structure) {
413
453
  return __awaiter(this, void 0, void 0, function* () {
414
454
  var _a;
455
+ log(_('Adding database structure for %s.%s', database, name));
415
456
  if (!((_a = structure === null || structure === void 0 ? void 0 : structure.keys) === null || _a === void 0 ? void 0 : _a.PRIMARY) || !(structure === null || structure === void 0 ? void 0 : structure.fields)) {
416
457
  throw new Error(_('The database structure for %s is not valid (missing keys, fields, or primary key)', name));
417
458
  }
@@ -419,42 +460,82 @@ const db = {
419
460
  this._structures[database] = {};
420
461
  }
421
462
  this._structures[database][name] = structure;
422
- // Only upgrade if the DB already exists/open and the store is missing
423
463
  const conn = this._connections[database];
424
- if (conn && !conn.objectStoreNames.contains(name)) {
425
- yield this.reopenWithUpgrade(database);
464
+ if (conn) {
465
+ if (!conn.objectStoreNames.contains(name)) {
466
+ return yield this.reopenWithUpgrade(database);
467
+ }
468
+ return conn;
469
+ }
470
+ // No live connection: inspect current DB and upgrade if needed.
471
+ const existingVersion = yield this.getExistingVersion(database);
472
+ const hasDbAlready = existingVersion > 0;
473
+ if (!hasDbAlready) {
474
+ yield this.open(database);
475
+ return this._connections[database];
476
+ }
477
+ // DB exists already: open temporarily and check if store exists
478
+ const tmp = yield this.openRaw(database);
479
+ const hasStore = tmp.objectStoreNames.contains(name);
480
+ tmp.close();
481
+ if (!hasStore) {
482
+ return yield this.reopenWithUpgrade(database);
483
+ }
484
+ return yield this.openRaw(database);
485
+ });
486
+ },
487
+ openRaw(name, version) {
488
+ return new Promise((resolve, reject) => {
489
+ if (!idb) {
490
+ reject(new Error(_('IndexedDB is not available')));
491
+ return;
426
492
  }
493
+ const req = version ? idb.open(name, version) : idb.open(name);
494
+ req.onsuccess = () => resolve(req.result);
495
+ req.onerror = () => reject(req.error);
496
+ req.onblocked = () => reject(new Error(_('IndexedDB open blocked for database %s', name)));
427
497
  });
428
498
  },
429
499
  remove(database, name) {
430
500
  return __awaiter(this, void 0, void 0, function* () {
431
- var _a;
432
- (_a = this._structures[database]) === null || _a === void 0 ? true : delete _a[name];
433
- const conn = this._connections[database];
434
- if (!conn) {
501
+ const currentStructure = this._structures[database];
502
+ if (!(currentStructure === null || currentStructure === void 0 ? void 0 : currentStructure[name])) {
435
503
  return;
436
504
  }
437
- const nextVersion = conn.version + 1;
438
- conn.close();
439
- delete this._connections[database];
440
- yield new Promise((resolve, reject) => {
441
- if (!idb) {
442
- reject(new Error(_('IndexedDB is not available')));
505
+ const old = currentStructure[name];
506
+ delete currentStructure[name];
507
+ try {
508
+ const conn = this._connections[database];
509
+ if (!conn) {
443
510
  return;
444
511
  }
445
- const req = idb.open(database, nextVersion);
446
- req.onupgradeneeded = () => {
447
- const dbInstance = req.result;
448
- if (dbInstance.objectStoreNames.contains(name)) {
449
- dbInstance.deleteObjectStore(name);
512
+ const nextVersion = conn.version + 1;
513
+ conn.close();
514
+ delete this._connections[database];
515
+ yield new Promise((resolve, reject) => {
516
+ if (!idb) {
517
+ reject(new Error(_('IndexedDB is not available')));
518
+ return;
450
519
  }
451
- };
452
- req.onsuccess = () => {
453
- this._connections[database] = req.result;
454
- resolve();
455
- };
456
- req.onerror = () => reject(req.error);
457
- });
520
+ const req = idb.open(database, nextVersion);
521
+ req.onupgradeneeded = () => {
522
+ const dbInstance = req.result;
523
+ if (dbInstance.objectStoreNames.contains(name)) {
524
+ dbInstance.deleteObjectStore(name);
525
+ }
526
+ };
527
+ req.onsuccess = () => {
528
+ this._connections[database] = req.result;
529
+ resolve();
530
+ };
531
+ req.onerror = () => reject(req.error);
532
+ req.onblocked = () => reject(new Error(_('Remove blocked for database %s', database)));
533
+ });
534
+ }
535
+ catch (e) {
536
+ currentStructure[name] = old;
537
+ throw e;
538
+ }
458
539
  });
459
540
  }
460
541
  };
package/dist/fn/init.js CHANGED
@@ -81,7 +81,7 @@ export default function init(cfg, force) {
81
81
  if (bbn.var.colors) {
82
82
  addColors(bbn.var.colors);
83
83
  }
84
- globalThis.document.addEventListener("visibilitychange", () => {
84
+ document.addEventListener("visibilitychange", () => {
85
85
  if (document.hidden) {
86
86
  bbn.env.isVisible = false;
87
87
  }
@@ -89,7 +89,7 @@ export default function init(cfg, force) {
89
89
  bbn.env.isVisible = true;
90
90
  }
91
91
  });
92
- globalThis.document.addEventListener("focus", (e) => {
92
+ document.addEventListener("focus", (e) => {
93
93
  if (e.target instanceof HTMLElement &&
94
94
  !e.target.classList.contains("bbn-no")) {
95
95
  bbn.env.focused = e.target;
@@ -97,7 +97,7 @@ export default function init(cfg, force) {
97
97
  bbn.env.isFocused = true;
98
98
  bbn.env.last_focus = timestamp();
99
99
  });
100
- globalThis.document.addEventListener("blur", (e) => {
100
+ document.addEventListener("blur", (e) => {
101
101
  if (e.target instanceof HTMLElement &&
102
102
  !e.target.classList.contains("bbn-no")) {
103
103
  bbn.env.focused = e.target;
@@ -105,29 +105,29 @@ export default function init(cfg, force) {
105
105
  bbn.env.isFocused = false;
106
106
  bbn.env.last_focus = timestamp();
107
107
  });
108
- globalThis.document.addEventListener("click", onActivity);
109
- globalThis.document.addEventListener("keydown", onActivity);
110
- globalThis.document.addEventListener("focusin", onFocus);
111
- globalThis.document.addEventListener("focusout", onFocus);
112
- globalThis.addEventListener("hashchange", () => {
108
+ document.addEventListener("click", onActivity);
109
+ document.addEventListener("keydown", onActivity);
110
+ document.addEventListener("focusin", onFocus);
111
+ document.addEventListener("focusout", onFocus);
112
+ window.addEventListener("hashchange", () => {
113
113
  bbn.env.hashChanged = new Date().getTime();
114
114
  }, false);
115
- globalThis.addEventListener("resize", () => {
115
+ window.addEventListener("resize", () => {
116
116
  resize();
117
117
  });
118
- globalThis.addEventListener("orientationchange", () => {
118
+ window.addEventListener("orientationchange", () => {
119
119
  resize();
120
120
  });
121
121
  resize();
122
122
  if (isMobile()) {
123
- globalThis.document.body.classList.add("bbn-mobile");
123
+ document.body.classList.add("bbn-mobile");
124
124
  if (isTabletDevice()) {
125
- globalThis.document.body.classList.add("bbn-tablet");
125
+ document.body.classList.add("bbn-tablet");
126
126
  }
127
127
  }
128
- if (globalThis.history) {
129
- globalThis.onpopstate = function (e) {
130
- let h = globalThis.history;
128
+ if (window.history) {
129
+ window.onpopstate = function (e) {
130
+ let h = window.history;
131
131
  if (!bbn.env.historyDisabled && h) {
132
132
  //e.preventDefault();
133
133
  if (bbn.fn.defaultHistoryFunction(h.state)) {
@@ -143,17 +143,17 @@ export default function init(cfg, force) {
143
143
  }
144
144
  };
145
145
  }
146
- globalThis.addEventListener('online', () => {
146
+ window.addEventListener('online', () => {
147
147
  bbn.env.online = true;
148
148
  });
149
- globalThis.addEventListener('offline', () => {
149
+ window.addEventListener('offline', () => {
150
150
  bbn.env.online = false;
151
151
  });
152
152
  bbn.env.isInit = true;
153
- globalThis.document.dispatchEvent(new Event("bbninit"));
154
- if (bbn.env.logging) {
155
- log("Logging in bbn is enabled");
156
- }
153
+ document.dispatchEvent(new Event("bbninit"));
154
+ }
155
+ if (bbn.env.logging) {
156
+ log("Logging in bbn is enabled");
157
157
  }
158
158
  }
159
159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbn/bbn",
3
- "version": "2.0.221",
3
+ "version": "2.0.222",
4
4
  "description": "Javascript toolkit",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",