@microsoft/applicationinsights-offlinechannel-js 0.1.0-nightly3.2402-06
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/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +14 -0
- package/LICENSE.TXT +21 -0
- package/PRIVACY +3 -0
- package/README.md +63 -0
- package/SECURITY.md +41 -0
- package/SUPPORT.md +14 -0
- package/dist/es5/applicationinsights-offlinechannel-js.js +6391 -0
- package/dist/es5/applicationinsights-offlinechannel-js.js.map +1 -0
- package/dist/es5/applicationinsights-offlinechannel-js.min.js +6 -0
- package/dist/es5/applicationinsights-offlinechannel-js.min.js.map +1 -0
- package/dist-es5/Helpers/Utils.js +185 -0
- package/dist-es5/Helpers/Utils.js.map +1 -0
- package/dist-es5/InMemoryBatch.js +64 -0
- package/dist-es5/InMemoryBatch.js.map +1 -0
- package/dist-es5/Interfaces/IInMemoryBatch.js +8 -0
- package/dist-es5/Interfaces/IInMemoryBatch.js.map +1 -0
- package/dist-es5/Interfaces/IOfflineBatch.js +9 -0
- package/dist-es5/Interfaces/IOfflineBatch.js.map +1 -0
- package/dist-es5/Interfaces/IOfflineIndexDb.js +8 -0
- package/dist-es5/Interfaces/IOfflineIndexDb.js.map +1 -0
- package/dist-es5/Interfaces/IOfflineProvider.js +8 -0
- package/dist-es5/Interfaces/IOfflineProvider.js.map +1 -0
- package/dist-es5/Interfaces/ISender.js +8 -0
- package/dist-es5/Interfaces/ISender.js.map +1 -0
- package/dist-es5/OfflineBatchHandler.js +343 -0
- package/dist-es5/OfflineBatchHandler.js.map +1 -0
- package/dist-es5/OfflineChannel.js +465 -0
- package/dist-es5/OfflineChannel.js.map +1 -0
- package/dist-es5/PayloadHelper.js +62 -0
- package/dist-es5/PayloadHelper.js.map +1 -0
- package/dist-es5/Providers/IndexDbHelper.js +626 -0
- package/dist-es5/Providers/IndexDbHelper.js.map +1 -0
- package/dist-es5/Providers/IndexDbProvider.js +468 -0
- package/dist-es5/Providers/IndexDbProvider.js.map +1 -0
- package/dist-es5/Providers/WebStorageProvider.js +463 -0
- package/dist-es5/Providers/WebStorageProvider.js.map +1 -0
- package/dist-es5/Sender.js +572 -0
- package/dist-es5/Sender.js.map +1 -0
- package/dist-es5/__DynamicConstants.js +80 -0
- package/dist-es5/__DynamicConstants.js.map +1 -0
- package/dist-es5/applicationinsights-offlinechannel-js.js +11 -0
- package/dist-es5/applicationinsights-offlinechannel-js.js.map +1 -0
- package/package.json +65 -0
- package/tsconfig.json +28 -0
- package/types/applicationinsights-offlinechannel-js.d.ts +605 -0
- package/types/applicationinsights-offlinechannel-js.namespaced.d.ts +601 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Application Insights JavaScript SDK - Offline Channel, 0.1.0-nightly3.2402-06
|
|
3
|
+
* Copyright (c) Microsoft and contributors. All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import dynamicProto from "@microsoft/dynamicproto-js";
|
|
8
|
+
import { getGlobalInst } from "@microsoft/applicationinsights-core-js";
|
|
9
|
+
import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createTaskScheduler, doAwait, doAwaitResponse } from "@nevware21/ts-async";
|
|
10
|
+
import { getGlobal, isFunction, isPromiseLike, isString } from "@nevware21/ts-utils";
|
|
11
|
+
import { _DYN_CONTINUE, _DYN_DB_HDL, _DYN_DB_NAME, _DYN_INDEX_OF, _DYN_IS_AVAILABLE, _DYN_KEY_RANGE, _DYN_LENGTH, _DYN_NAME, _DYN_ONERROR, _DYN_ONSUCCESS, _DYN_OPEN_CURSOR, _DYN_OPEN_STORE, _DYN_PUSH, _DYN_REASON, _DYN_REJECTED, _DYN_REMOVE, _DYN_SPLICE, _DYN_SPLIT, _DYN_SUBSTRING, _DYN_THEN, _DYN_TRANSACTION, _DYN_VALUE } from "../__DynamicConstants";
|
|
12
|
+
//TODO: move all const to one file
|
|
13
|
+
//TODO: handle db names
|
|
14
|
+
var IndexedDBNames = ["indexedDB" /*, 'mozIndexedDB', 'webkitIndexedDB', 'msIndexedDb'*/];
|
|
15
|
+
var DbReadWrite = "readwrite";
|
|
16
|
+
var Result = "result";
|
|
17
|
+
var ErrorMessageUnableToOpenDb = "DBError: Unable to open database";
|
|
18
|
+
var ErrorMessageDbUpgradeRequired = "DBError: Database upgrade required";
|
|
19
|
+
var ErrorMessageDbNotOpen = "Database is not open";
|
|
20
|
+
var ErrorMessageDbDoesNotExist = "DBError: Database does not exist";
|
|
21
|
+
var ErrorMessageFailedToDeleteDatabase = "DBError: Failed to delete the database";
|
|
22
|
+
var ErrorMessageDbNotSupported = "DBError: Feature not supported";
|
|
23
|
+
var ErrorMessageFailedToOpenCursor = "DBError: Failed to Open Cursor";
|
|
24
|
+
//window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
|
|
25
|
+
//window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
|
|
26
|
+
// By placing this variable here it becomes a global hidden static
|
|
27
|
+
/**
|
|
28
|
+
* This is used to enforce sequential access to the IndexedDb, so that all operations don't interfere
|
|
29
|
+
* with each other, this is REALLY useful to ensure that any previous operation has completed before
|
|
30
|
+
* subsequent operations are completed -- especially for testing using different IndexedDbHelper instances.
|
|
31
|
+
*/
|
|
32
|
+
var _dbContext = [];
|
|
33
|
+
/**
|
|
34
|
+
* Constructs the IDbContext instance
|
|
35
|
+
* @param dbName The current database name
|
|
36
|
+
* @param diagLog The diagnostics logger to use
|
|
37
|
+
*/
|
|
38
|
+
function _getDbContext(dbName, diagLog) {
|
|
39
|
+
var _a;
|
|
40
|
+
var dbCtx = null;
|
|
41
|
+
for (var lp = 0; lp < _dbContext[_DYN_LENGTH /* @min:%2elength */]; lp++) {
|
|
42
|
+
dbCtx = _dbContext[lp];
|
|
43
|
+
if (dbCtx[_DYN_NAME /* @min:%2ename */] === dbName) {
|
|
44
|
+
return dbCtx;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Create the global handle for the database
|
|
48
|
+
dbCtx = (_a = {},
|
|
49
|
+
_a[_DYN_NAME /* @min:name */] = dbName,
|
|
50
|
+
_a.sch = createTaskScheduler(createAsyncPromise, "IndexedDbHelper[" + dbName + "]"),
|
|
51
|
+
_a.dbHdl = [],
|
|
52
|
+
_a.add = function (db) {
|
|
53
|
+
dbCtx.dbHdl[_DYN_PUSH /* @min:%2epush */](db);
|
|
54
|
+
_debugLog(dbName, "- dbOpened (add) -- hdls [" + dbCtx.dbHdl[_DYN_LENGTH /* @min:%2elength */] + "]");
|
|
55
|
+
},
|
|
56
|
+
_a[_DYN_REMOVE /* @min:remove */] = function (db) {
|
|
57
|
+
var hdls = dbCtx[_DYN_DB_HDL /* @min:%2edbHdl */];
|
|
58
|
+
for (var lp = 0; lp < hdls[_DYN_LENGTH /* @min:%2elength */]; lp++) {
|
|
59
|
+
if (hdls[lp] === db) {
|
|
60
|
+
hdls[_DYN_SPLICE /* @min:%2esplice */](lp, 1);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
_debugLog(dbName, "- dbClosed (remove) -- hdls [" + dbCtx.dbHdl[_DYN_LENGTH /* @min:%2elength */] + "]");
|
|
65
|
+
},
|
|
66
|
+
_a.isOpen = function () {
|
|
67
|
+
return dbCtx.dbHdl[_DYN_LENGTH /* @min:%2elength */] > 0;
|
|
68
|
+
},
|
|
69
|
+
_a.openHdl = function () {
|
|
70
|
+
if (dbCtx.dbHdl[_DYN_LENGTH /* @min:%2elength */] > 0) {
|
|
71
|
+
return dbCtx[_DYN_DB_HDL /* @min:%2edbHdl */][0];
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
},
|
|
75
|
+
_a);
|
|
76
|
+
_dbContext[_DYN_PUSH /* @min:%2epush */](dbCtx);
|
|
77
|
+
return dbCtx;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Schedule an event that will execute the startEvent after all outstanding events are resolved or if any event rejects the optional
|
|
81
|
+
* rejectEvent will be executed. This is used to ensure that we don't attempt to execute events out of order such as attempting to removed
|
|
82
|
+
* an event from the indexedDb before the insertion of the event has completed. Only one of the startEvent or unableToStateEvent callbacks
|
|
83
|
+
* functions will be called.
|
|
84
|
+
* @param startEvent The event to execute after all outstanding events are complete, may be called synchronously or asynchronously.
|
|
85
|
+
* @param actionName The name of the action being performed
|
|
86
|
+
*/
|
|
87
|
+
function _scheduleEvent(dbName, actionName, startEvent, evtTimeOut) {
|
|
88
|
+
// Create or fetch the current scheduler for this dbName
|
|
89
|
+
var dbCtx = _getDbContext(dbName);
|
|
90
|
+
return dbCtx.sch.queue(startEvent, actionName, evtTimeOut);
|
|
91
|
+
}
|
|
92
|
+
// TODO: move to common to be able to used by lds
|
|
93
|
+
export function getDbFactory() {
|
|
94
|
+
var global = getGlobal() || {};
|
|
95
|
+
var dbFactory = null;
|
|
96
|
+
if (global) {
|
|
97
|
+
try {
|
|
98
|
+
for (var lp = 0; lp < IndexedDBNames[_DYN_LENGTH /* @min:%2elength */]; lp++) {
|
|
99
|
+
dbFactory = global[IndexedDBNames[lp]];
|
|
100
|
+
if (dbFactory && isFunction(dbFactory.open)) {
|
|
101
|
+
return dbFactory;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
dbFactory = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return dbFactory;
|
|
110
|
+
}
|
|
111
|
+
function _debugLog(dbName, message) {
|
|
112
|
+
// Only log if running within test harness
|
|
113
|
+
if (getGlobalInst("QUnit")) {
|
|
114
|
+
// tslint:disable-next-line:no-console
|
|
115
|
+
console && console.log("IndexedDbHelper [" + dbName + "] " + message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Helper method to map an Event rejection to a reject with a message, this is mainly for terminal errors where the
|
|
120
|
+
* IndexedDb API returns an event which we are going to ignore
|
|
121
|
+
* @param rejectMessage
|
|
122
|
+
* @param rejectFunc
|
|
123
|
+
*/
|
|
124
|
+
function _eventReject(dbName, rejectMessage, rejectFunc, evtName) {
|
|
125
|
+
return function (evt) {
|
|
126
|
+
rejectFunc(new Error(rejectMessage));
|
|
127
|
+
_debugLog(dbName, "[" + evtName + "] event rejected");
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// This helper is designed to allow multiple database implementation
|
|
131
|
+
// The IndexedDB provider will be using only one database with different stores.
|
|
132
|
+
// for each transaction, will open a new connection
|
|
133
|
+
var IndexedDbHelper = /** @class */ (function () {
|
|
134
|
+
function IndexedDbHelper(diagLog) {
|
|
135
|
+
var _dbFactory = getDbFactory() || null;
|
|
136
|
+
dynamicProto(IndexedDbHelper, this, function (_this) {
|
|
137
|
+
_this[_DYN_IS_AVAILABLE /* @min:%2eisAvailable */] = function () {
|
|
138
|
+
return !!_dbFactory;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Schedules the opening of the database if not already open
|
|
142
|
+
*/
|
|
143
|
+
_this.openDb = function (dbName, dbVersion, processFunc, versionChangeFunc) {
|
|
144
|
+
// Schedule the database to be opened
|
|
145
|
+
return _scheduleEvent(dbName, "openDb", function (evtName) {
|
|
146
|
+
return createAsyncPromise(function (openResolve, openReject) {
|
|
147
|
+
var createdNewDb = false;
|
|
148
|
+
function _createDbCtx(dbContext, db, dbOpenRequest, isNew, isUpgrade) {
|
|
149
|
+
var _a;
|
|
150
|
+
var crDbCtx = (_a = {
|
|
151
|
+
db: db
|
|
152
|
+
},
|
|
153
|
+
_a[_DYN_DB_NAME /* @min:dbName */] = dbName,
|
|
154
|
+
_a.dbVersion = dbVersion,
|
|
155
|
+
_a.ctx = null,
|
|
156
|
+
_a.isNew = isNew,
|
|
157
|
+
_a.txn = dbOpenRequest ? dbOpenRequest[_DYN_TRANSACTION /* @min:%2etransaction */] : null // Special case see the versionChangeFunc usage below
|
|
158
|
+
,
|
|
159
|
+
_a);
|
|
160
|
+
if (!isUpgrade) {
|
|
161
|
+
crDbCtx[_DYN_OPEN_STORE /* @min:%2eopenStore */] = function (eventTable, doAction) {
|
|
162
|
+
return _openStore(crDbCtx, eventTable, doAction);
|
|
163
|
+
};
|
|
164
|
+
crDbCtx[_DYN_OPEN_CURSOR /* @min:%2eopenCursor */] = function (eventTable, query, cursorFunc) {
|
|
165
|
+
return _openCursor(crDbCtx, eventTable, query, cursorFunc);
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return crDbCtx;
|
|
169
|
+
}
|
|
170
|
+
// TODO: add function to handle version change
|
|
171
|
+
function _databaseUpgrade(db, dbOpenRequest, ev) {
|
|
172
|
+
_debugLog(dbName, "db upgrade called");
|
|
173
|
+
var upgDbCtx = _createDbCtx(null, db, dbOpenRequest, true, true);
|
|
174
|
+
if (!versionChangeFunc) {
|
|
175
|
+
try {
|
|
176
|
+
dbOpenRequest[_DYN_TRANSACTION /* @min:%2etransaction */] && dbOpenRequest[_DYN_TRANSACTION /* @min:%2etransaction */].abort();
|
|
177
|
+
dbOpenRequest.result && dbOpenRequest.result.close(); // close database to unblock others
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
openReject(new Error(ErrorMessageDbUpgradeRequired));
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
createdNewDb = true;
|
|
185
|
+
doAwaitResponse(versionChangeFunc(upgDbCtx), function (response) {
|
|
186
|
+
if (!response[_DYN_REJECTED /* @min:%2erejected */]) {
|
|
187
|
+
// Special case handling, when a DB is first created calling createObjectStore() will
|
|
188
|
+
// automatically start a version change transaction which will block all other transactions
|
|
189
|
+
// from getting created, so we save the auto opened on here for reuse as part of opening the store
|
|
190
|
+
_debugLog(upgDbCtx[_DYN_DB_NAME /* @min:%2edbName */], "on version change success");
|
|
191
|
+
if (!upgDbCtx.txn) {
|
|
192
|
+
upgDbCtx.txn = dbOpenRequest[_DYN_TRANSACTION /* @min:%2etransaction */];
|
|
193
|
+
_debugLog(upgDbCtx[_DYN_DB_NAME /* @min:%2edbName */], "added open request");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Abort the upgrade event
|
|
198
|
+
try {
|
|
199
|
+
dbOpenRequest[_DYN_TRANSACTION /* @min:%2etransaction */] && dbOpenRequest[_DYN_TRANSACTION /* @min:%2etransaction */].abort();
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
openReject(response[_DYN_REASON /* @min:%2ereason */]);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function _databaseOpen(db, dbOpenRequest) {
|
|
208
|
+
// Save the IDBDatabase handle to the global reference (so we can make sure we can close/delete the Db)
|
|
209
|
+
// Also used to track the number of times the DB has been opened
|
|
210
|
+
var opDbCtx = _getDbContext(dbName);
|
|
211
|
+
opDbCtx.add(db);
|
|
212
|
+
db.onabort = function (evt) {
|
|
213
|
+
_debugLog(dbName, "onabort -- closing the Db");
|
|
214
|
+
opDbCtx[_DYN_REMOVE /* @min:%2eremove */](db);
|
|
215
|
+
};
|
|
216
|
+
db[_DYN_ONERROR /* @min:%2eonerror */] = function (evt) {
|
|
217
|
+
_debugLog(dbName, "onerror -- closing the Db");
|
|
218
|
+
opDbCtx[_DYN_REMOVE /* @min:%2eremove */](db);
|
|
219
|
+
};
|
|
220
|
+
db.onclose = function (evt) {
|
|
221
|
+
_debugLog(dbName, "onclose -- closing the Db");
|
|
222
|
+
opDbCtx[_DYN_REMOVE /* @min:%2eremove */](db);
|
|
223
|
+
};
|
|
224
|
+
db.onversionchange = function (evt) {
|
|
225
|
+
_debugLog(dbName, "onversionchange -- force closing the Db");
|
|
226
|
+
db.close();
|
|
227
|
+
opDbCtx[_DYN_REMOVE /* @min:%2eremove */](db);
|
|
228
|
+
};
|
|
229
|
+
var openDbCtx = null;
|
|
230
|
+
var dbHdl = null;
|
|
231
|
+
if (opDbCtx.dbHdl[_DYN_LENGTH /* @min:%2elength */] > 0) {
|
|
232
|
+
dbHdl = opDbCtx[_DYN_DB_HDL /* @min:%2edbHdl */][0];
|
|
233
|
+
}
|
|
234
|
+
openDbCtx = _createDbCtx(opDbCtx, dbHdl, dbOpenRequest, createdNewDb);
|
|
235
|
+
try {
|
|
236
|
+
// Database has been opened
|
|
237
|
+
doAwait(processFunc(openDbCtx), openResolve, openReject);
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
openReject(e);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
var dbCtx = _getDbContext(dbName);
|
|
244
|
+
if (_dbFactory == null) {
|
|
245
|
+
openReject(new Error("No available storage factory"));
|
|
246
|
+
}
|
|
247
|
+
else if (dbCtx.isOpen()) {
|
|
248
|
+
// Database is already open
|
|
249
|
+
var openDbCtx = _createDbCtx(dbCtx, dbCtx.openHdl(), null, false);
|
|
250
|
+
doAwait(processFunc(openDbCtx), openResolve, openReject);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
var dbOpenRequest_1 = _dbFactory.open(dbName, dbVersion);
|
|
254
|
+
if (!dbOpenRequest_1) {
|
|
255
|
+
throw new Error("missing API"); // in case, some corners case (such as private mode for certain browsers) does not support open db
|
|
256
|
+
}
|
|
257
|
+
// We can't open the database, possible issues are
|
|
258
|
+
// - We are attempting to open the db as a different version but it's already open
|
|
259
|
+
dbOpenRequest_1.onblocked = function (evt) {
|
|
260
|
+
_debugLog(dbName, "Db Open Blocked event [" + evtName + "] - " + (dbOpenRequest_1.error || ""));
|
|
261
|
+
openReject(new Error(ErrorMessageUnableToOpenDb));
|
|
262
|
+
};
|
|
263
|
+
dbOpenRequest_1[_DYN_ONERROR /* @min:%2eonerror */] = function (evt) {
|
|
264
|
+
_debugLog(dbName, "Db Open Error event [" + evtName + "] - " + (dbOpenRequest_1.error || ""));
|
|
265
|
+
openReject(new Error(ErrorMessageUnableToOpenDb));
|
|
266
|
+
};
|
|
267
|
+
dbOpenRequest_1.onupgradeneeded = function (evt) {
|
|
268
|
+
_debugLog(dbName, "Db Open Create/Upgrade needed event [" + evtName + "]");
|
|
269
|
+
try {
|
|
270
|
+
var db = evt.target[Result] || dbOpenRequest_1.result;
|
|
271
|
+
if (!db) {
|
|
272
|
+
_debugLog(dbName, "no db");
|
|
273
|
+
openReject(new Error(ErrorMessageUnableToOpenDb));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
_databaseUpgrade(db, dbOpenRequest_1, evt);
|
|
277
|
+
}
|
|
278
|
+
catch (e) {
|
|
279
|
+
_eventReject(dbName, ErrorMessageUnableToOpenDb, openReject, evtName)(e);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
dbOpenRequest_1[_DYN_ONSUCCESS /* @min:%2eonsuccess */] = function (evt) {
|
|
283
|
+
_debugLog(dbName, "Db Open sucess [" + evtName + "]");
|
|
284
|
+
var db = evt.target[Result];
|
|
285
|
+
if (!db) {
|
|
286
|
+
openReject(new Error(ErrorMessageUnableToOpenDb));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
_databaseOpen(db, dbOpenRequest_1);
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
};
|
|
295
|
+
_this.closeDb = function (dbName) {
|
|
296
|
+
// Schedule the close so we don't interrupt an previous scheduled operations
|
|
297
|
+
_debugLog(dbName, "close db");
|
|
298
|
+
_scheduleEvent(dbName, "closeDb", function (evtName) {
|
|
299
|
+
var dbCtx = _getDbContext(dbName);
|
|
300
|
+
var dbHdls = dbCtx[_DYN_DB_HDL /* @min:%2edbHdl */];
|
|
301
|
+
var len = dbHdls[_DYN_LENGTH /* @min:%2elength */];
|
|
302
|
+
if (len > 0) {
|
|
303
|
+
for (var lp = 0; lp < len; lp++) {
|
|
304
|
+
// Just call close the db.onclose() event should take care of decrementing and removing the references
|
|
305
|
+
dbHdls[lp].close();
|
|
306
|
+
}
|
|
307
|
+
dbCtx[_DYN_DB_HDL /* @min:%2edbHdl */] = [];
|
|
308
|
+
}
|
|
309
|
+
return 1;
|
|
310
|
+
}).catch(function (reason) {
|
|
311
|
+
// Handle promise rejection to avoid an unhandled rejection event
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
_this.deleteDb = function (dbName) {
|
|
315
|
+
if (_dbFactory == null) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
return _scheduleEvent(dbName, "deleteDb", function (evtName) {
|
|
319
|
+
// Implicitly close any open db first as this WILL block the deleting
|
|
320
|
+
var dbCtx = _getDbContext(dbName);
|
|
321
|
+
var dbHdls = dbCtx[_DYN_DB_HDL /* @min:%2edbHdl */];
|
|
322
|
+
var len = dbHdls[_DYN_LENGTH /* @min:%2elength */];
|
|
323
|
+
if (len > 0) {
|
|
324
|
+
_debugLog(dbName, "Db is open [" + len + "] force closing");
|
|
325
|
+
for (var lp = 0; lp < len; lp++) {
|
|
326
|
+
// Just call close the db.onclose() event should take care of decrementing and removing the references
|
|
327
|
+
dbHdls[lp].close();
|
|
328
|
+
}
|
|
329
|
+
// Clear all of the existing handles as we have forced closed them and for compatibility we can't
|
|
330
|
+
// rely on the db onclose event
|
|
331
|
+
dbCtx[_DYN_DB_HDL /* @min:%2edbHdl */] = [];
|
|
332
|
+
}
|
|
333
|
+
return createAsyncPromise(function (deleteResolve, deleteReject) {
|
|
334
|
+
// Attempting to delete the Db, only after we wait so that any outstanding operations can finish
|
|
335
|
+
setTimeout(function () {
|
|
336
|
+
try {
|
|
337
|
+
_debugLog(dbName, "[" + evtName + "] starting");
|
|
338
|
+
var dbRequest = _dbFactory.deleteDatabase(dbName);
|
|
339
|
+
dbRequest[_DYN_ONERROR /* @min:%2eonerror */] = function (evt) {
|
|
340
|
+
deleteReject(new Error(ErrorMessageFailedToDeleteDatabase));
|
|
341
|
+
};
|
|
342
|
+
dbRequest.onblocked = function (evt) {
|
|
343
|
+
deleteReject(new Error(ErrorMessageFailedToDeleteDatabase));
|
|
344
|
+
};
|
|
345
|
+
dbRequest.onupgradeneeded = function (evt) {
|
|
346
|
+
deleteReject(new Error(ErrorMessageFailedToDeleteDatabase));
|
|
347
|
+
};
|
|
348
|
+
dbRequest[_DYN_ONSUCCESS /* @min:%2eonsuccess */] = function (evt) {
|
|
349
|
+
_debugLog(dbName, "[" + evtName + "] complete");
|
|
350
|
+
deleteResolve(true);
|
|
351
|
+
};
|
|
352
|
+
_debugLog(dbName, "[" + evtName + "] started");
|
|
353
|
+
}
|
|
354
|
+
catch (e) {
|
|
355
|
+
deleteReject(new Error(ErrorMessageFailedToDeleteDatabase + " - " + e));
|
|
356
|
+
}
|
|
357
|
+
}, 0);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
_this.getDbDetails = function (dbName) {
|
|
362
|
+
return _scheduleEvent(dbName, "getDbDetails", function (evtName) {
|
|
363
|
+
if (_dbFactory == null || !_dbFactory.databases) {
|
|
364
|
+
// Either IndexedDb is not supported or databases is not supported
|
|
365
|
+
return createAsyncRejectedPromise(new Error(ErrorMessageDbNotSupported));
|
|
366
|
+
}
|
|
367
|
+
return createAsyncPromise(function (databasesResolve, databasesReject) {
|
|
368
|
+
// databases() is still experimental, so it's not fully available
|
|
369
|
+
// The promise will reject if there is a JS error
|
|
370
|
+
var dbPromise = _dbFactory.databases();
|
|
371
|
+
dbPromise[_DYN_THEN /* @min:%2ethen */](function (databases) {
|
|
372
|
+
for (var lp = 0; lp < databases[_DYN_LENGTH /* @min:%2elength */]; lp++) {
|
|
373
|
+
if (databases[lp][_DYN_NAME /* @min:%2ename */] === dbName) {
|
|
374
|
+
databasesResolve(databases[lp]);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
databasesReject(new Error(ErrorMessageDbDoesNotExist));
|
|
379
|
+
}, databasesReject);
|
|
380
|
+
});
|
|
381
|
+
}, 2000);
|
|
382
|
+
};
|
|
383
|
+
function _createStoreContext(openDbCtx, eventTable) {
|
|
384
|
+
// Save the current handle so we close the correct one during the transaction events
|
|
385
|
+
var dbHdl = openDbCtx.db || null;
|
|
386
|
+
// Check if the openDb event created a transaction that we should reuse
|
|
387
|
+
var tx = dbHdl && dbHdl[_DYN_TRANSACTION /* @min:%2etransaction */](eventTable, DbReadWrite);
|
|
388
|
+
if (tx) {
|
|
389
|
+
// The transaction was aborted and therefore the adding of the event failed
|
|
390
|
+
tx.onabort = function () {
|
|
391
|
+
// add log
|
|
392
|
+
};
|
|
393
|
+
tx[_DYN_ONERROR /* @min:%2eonerror */] = function () {
|
|
394
|
+
// add log
|
|
395
|
+
};
|
|
396
|
+
// Note we don't listen for the transaction onComplete event as we don't have any value
|
|
397
|
+
// to resolve the promise with, we are relying on the doAction() to resolve and the exception
|
|
398
|
+
// handling below to ensure we don't deadlock.
|
|
399
|
+
tx.oncomplete = function () {
|
|
400
|
+
// We need to capture the transaction close event as not all browsers are triggering the db onclose event
|
|
401
|
+
_debugLog(openDbCtx[_DYN_DB_NAME /* @min:%2edbName */], "txn.oncomplete");
|
|
402
|
+
};
|
|
403
|
+
// Ok, so now we have the transaction handling setup lets try and store the event
|
|
404
|
+
return {
|
|
405
|
+
db: openDbCtx,
|
|
406
|
+
store: tx.objectStore(eventTable),
|
|
407
|
+
tx: tx,
|
|
408
|
+
tbl: eventTable,
|
|
409
|
+
openCursor: function (query, processFunc) {
|
|
410
|
+
return _openCursor(openDbCtx, eventTable, query, processFunc);
|
|
411
|
+
},
|
|
412
|
+
newTransaction: function (doAction) {
|
|
413
|
+
return _openStore(openDbCtx, eventTable, doAction);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Opens the specific store for the database
|
|
421
|
+
* @param openDbCtx
|
|
422
|
+
* @param eventTable
|
|
423
|
+
* @param doAction
|
|
424
|
+
*/
|
|
425
|
+
function _openStore(openDbCtx, eventTable, doAction) {
|
|
426
|
+
// While the open DB promise may have been resolved we still might not have opened the DB (This is to ensure that
|
|
427
|
+
// non-critical failures don't cause event execution out of order)
|
|
428
|
+
if (!openDbCtx || !openDbCtx.db) {
|
|
429
|
+
// Database is not open so pass the only option is to resolve the event so it's passed onto the next on the event to the next chain
|
|
430
|
+
return createAsyncRejectedPromise(new Error(ErrorMessageDbNotOpen));
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
// Perform the transaction action
|
|
434
|
+
var result = doAction(_createStoreContext(openDbCtx, eventTable));
|
|
435
|
+
if (isPromiseLike(result)) {
|
|
436
|
+
return result;
|
|
437
|
+
}
|
|
438
|
+
return createAsyncResolvedPromise(result);
|
|
439
|
+
}
|
|
440
|
+
catch (e) {
|
|
441
|
+
return createAsyncRejectedPromise(e);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function _openCursor(openDbCtx, eventTable, query, processFunc) {
|
|
445
|
+
// While the open DB promise may have been resolved we still might not have opened the DB (This is to ensure that
|
|
446
|
+
// non-critical failures don't cause event execution out of order)
|
|
447
|
+
if (!openDbCtx || !openDbCtx.db) {
|
|
448
|
+
// Database is not open so pass the only option is to resolve the event so it's passed onto the next on the event to the next chain
|
|
449
|
+
return createAsyncRejectedPromise(new Error(ErrorMessageDbNotOpen));
|
|
450
|
+
}
|
|
451
|
+
var simpleQuery = null;
|
|
452
|
+
if (query && isString(query)) {
|
|
453
|
+
simpleQuery = new SimpleQuery(query);
|
|
454
|
+
}
|
|
455
|
+
else if (query && query.isMatch) { // simple check to make sure this is a IIndexedDbSimpleQuery
|
|
456
|
+
simpleQuery = query;
|
|
457
|
+
}
|
|
458
|
+
return createAsyncPromise(function (openCursorResolve, openCursorReject) {
|
|
459
|
+
var values = [];
|
|
460
|
+
var cursorRequest = null;
|
|
461
|
+
var queryKeyRange = null;
|
|
462
|
+
if (simpleQuery && simpleQuery[_DYN_KEY_RANGE /* @min:%2ekeyRange */]) {
|
|
463
|
+
queryKeyRange = simpleQuery[_DYN_KEY_RANGE /* @min:%2ekeyRange */]();
|
|
464
|
+
}
|
|
465
|
+
var storeCtx = _createStoreContext(openDbCtx, eventTable);
|
|
466
|
+
if (queryKeyRange) {
|
|
467
|
+
cursorRequest = storeCtx.store[_DYN_OPEN_CURSOR /* @min:%2eopenCursor */](queryKeyRange);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
cursorRequest = storeCtx.store[_DYN_OPEN_CURSOR /* @min:%2eopenCursor */]();
|
|
471
|
+
}
|
|
472
|
+
cursorRequest[_DYN_ONERROR /* @min:%2eonerror */] = _eventReject(storeCtx.db[_DYN_DB_NAME /* @min:%2edbName */], ErrorMessageFailedToOpenCursor, openCursorReject, "openCursor");
|
|
473
|
+
cursorRequest[_DYN_ONSUCCESS /* @min:%2eonsuccess */] = function (evt) {
|
|
474
|
+
var _a;
|
|
475
|
+
// Cursor was open/next iteration
|
|
476
|
+
var cursor = evt.target[Result];
|
|
477
|
+
if (!cursor) {
|
|
478
|
+
// This occurs when we get to the end of the cursor iteration
|
|
479
|
+
openCursorResolve(values);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
var processCursorState = (_a = {
|
|
483
|
+
store: storeCtx,
|
|
484
|
+
cursor: cursor
|
|
485
|
+
},
|
|
486
|
+
_a[_DYN_CONTINUE /* @min:continue */] = function () {
|
|
487
|
+
cursor[_DYN_CONTINUE /* @min:%2econtinue */]();
|
|
488
|
+
},
|
|
489
|
+
_a.done = function () {
|
|
490
|
+
openCursorResolve(values);
|
|
491
|
+
} // Stops the cursor processing
|
|
492
|
+
,
|
|
493
|
+
_a);
|
|
494
|
+
var value = cursor[_DYN_VALUE /* @min:%2evalue */];
|
|
495
|
+
if (simpleQuery && !simpleQuery.isMatch(value)) {
|
|
496
|
+
processCursorState[_DYN_CONTINUE /* @min:%2econtinue */]();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (processFunc) {
|
|
500
|
+
try {
|
|
501
|
+
switch (processFunc(processCursorState, value, values)) {
|
|
502
|
+
case 2 /* CursorProcessResult.Complete */:
|
|
503
|
+
openCursorResolve(values);
|
|
504
|
+
break;
|
|
505
|
+
case 1 /* CursorProcessResult.Waiting */:
|
|
506
|
+
// The process method now controls whether th
|
|
507
|
+
break;
|
|
508
|
+
case 0 /* CursorProcessResult.Continue */:
|
|
509
|
+
default:
|
|
510
|
+
processCursorState[_DYN_CONTINUE /* @min:%2econtinue */]();
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
catch (ex) {
|
|
515
|
+
// Make sure the reject the promise if the processFunc callback throws unexpectable
|
|
516
|
+
openCursorReject(ex);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
values[_DYN_PUSH /* @min:%2epush */](value);
|
|
521
|
+
processCursorState[_DYN_CONTINUE /* @min:%2econtinue */]();
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
// Removed Stub for IndexedDbHelper.prototype.isAvailable.
|
|
529
|
+
// Removed Stub for IndexedDbHelper.prototype.openDb.
|
|
530
|
+
// Removed Stub for IndexedDbHelper.prototype.closeDb.
|
|
531
|
+
// Removed Stub for IndexedDbHelper.prototype.deleteDb.
|
|
532
|
+
// Removed Stub for IndexedDbHelper.prototype.getDbDetails.
|
|
533
|
+
// This is a workaround for an IE bug when using dynamicProto() with classes that don't have any
|
|
534
|
+
// non-dynamic functions or static properties/functions when using uglify-js to minify the resulting code.
|
|
535
|
+
IndexedDbHelper.__ieDyn=1;
|
|
536
|
+
|
|
537
|
+
return IndexedDbHelper;
|
|
538
|
+
}());
|
|
539
|
+
export { IndexedDbHelper };
|
|
540
|
+
/**
|
|
541
|
+
* A simple query interface to provide a simple cursor query (IDBKeyRange) key range and matching.
|
|
542
|
+
* Used by the openCursor() method.
|
|
543
|
+
*/
|
|
544
|
+
var SimpleQuery = /** @class */ (function () {
|
|
545
|
+
function SimpleQuery(theQuery) {
|
|
546
|
+
var _queryCols = [];
|
|
547
|
+
var _keyRange = null;
|
|
548
|
+
dynamicProto(SimpleQuery, this, function (_this) {
|
|
549
|
+
_this[_DYN_KEY_RANGE /* @min:%2ekeyRange */] = function () {
|
|
550
|
+
return _keyRange;
|
|
551
|
+
};
|
|
552
|
+
_this.parseQuery = function (query) {
|
|
553
|
+
_queryCols = [];
|
|
554
|
+
if (query) {
|
|
555
|
+
var items = query[_DYN_SPLIT /* @min:%2esplit */](";");
|
|
556
|
+
for (var lp = 0; lp < items[_DYN_LENGTH /* @min:%2elength */]; lp++) {
|
|
557
|
+
var item = items[lp];
|
|
558
|
+
var idx = item[_DYN_INDEX_OF /* @min:%2eindexOf */]("=");
|
|
559
|
+
if (idx !== -1) {
|
|
560
|
+
var key = item[_DYN_SUBSTRING /* @min:%2esubstring */](0, idx);
|
|
561
|
+
var value = item[_DYN_SUBSTRING /* @min:%2esubstring */](idx + 1);
|
|
562
|
+
if (key[_DYN_INDEX_OF /* @min:%2eindexOf */]("#") === 0) {
|
|
563
|
+
key = key[_DYN_SUBSTRING /* @min:%2esubstring */](1);
|
|
564
|
+
if (!_keyRange) {
|
|
565
|
+
_keyRange = IDBKeyRange.bound(value, value + "\uffff");
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
_this.startsWith(key, value);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
_this.startsWith = function (columnName, value) {
|
|
574
|
+
var _a;
|
|
575
|
+
_queryCols[_DYN_PUSH /* @min:%2epush */]((_a = {},
|
|
576
|
+
_a[_DYN_NAME /* @min:name */] = columnName,
|
|
577
|
+
_a[_DYN_VALUE /* @min:value */] = value,
|
|
578
|
+
_a.type = 0 /* ValueQueryType.StartsWith */,
|
|
579
|
+
_a));
|
|
580
|
+
};
|
|
581
|
+
_this.contains = function (columnName, value) {
|
|
582
|
+
var _a;
|
|
583
|
+
_queryCols[_DYN_PUSH /* @min:%2epush */]((_a = {},
|
|
584
|
+
_a[_DYN_NAME /* @min:name */] = columnName,
|
|
585
|
+
_a[_DYN_VALUE /* @min:value */] = value,
|
|
586
|
+
_a.type = 1 /* ValueQueryType.Contains */,
|
|
587
|
+
_a));
|
|
588
|
+
};
|
|
589
|
+
_this.isMatch = function (value) {
|
|
590
|
+
// No query restriction so everything matches
|
|
591
|
+
if (!_queryCols || _queryCols[_DYN_LENGTH /* @min:%2elength */] === 0) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
if (!value) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
for (var lp = 0; lp < _queryCols[_DYN_LENGTH /* @min:%2elength */]; lp++) {
|
|
598
|
+
var query = _queryCols[lp];
|
|
599
|
+
var chkValue = value[query.name];
|
|
600
|
+
if (chkValue) {
|
|
601
|
+
if (query.type === 0 /* ValueQueryType.StartsWith */) {
|
|
602
|
+
if (chkValue.indexOf(query[_DYN_VALUE /* @min:%2evalue */]) !== 0) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
else if (query.type === 1 /* ValueQueryType.Contains */) {
|
|
607
|
+
if (chkValue.indexOf(query[_DYN_VALUE /* @min:%2evalue */]) === -1) {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return true;
|
|
614
|
+
};
|
|
615
|
+
if (theQuery) {
|
|
616
|
+
_this.parseQuery(theQuery);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
// This is a workaround for an IE bug when using dynamicProto() with classes that don't have any
|
|
621
|
+
// non-dynamic functions or static properties/functions when using uglify-js to minify the resulting code.
|
|
622
|
+
SimpleQuery.__ieDyn=1;
|
|
623
|
+
|
|
624
|
+
return SimpleQuery;
|
|
625
|
+
}());
|
|
626
|
+
//# sourceMappingURL=IndexDbHelper.js.map
|