@cloudbase/database 0.9.17-beta → 0.9.19

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.
Files changed (218) hide show
  1. package/README.md +32 -10
  2. package/dist/commonjs/ObjectId/index.d.ts +11 -0
  3. package/dist/commonjs/ObjectId/index.js +21 -0
  4. package/dist/commonjs/aggregate.d.ts +29 -29
  5. package/dist/commonjs/aggregate.js +156 -146
  6. package/dist/commonjs/collection.d.ts +9 -9
  7. package/dist/commonjs/collection.js +46 -46
  8. package/dist/commonjs/command.d.ts +175 -175
  9. package/dist/commonjs/command.js +298 -298
  10. package/dist/commonjs/commands/logic.d.ts +24 -24
  11. package/dist/commonjs/commands/logic.js +88 -88
  12. package/dist/commonjs/commands/query.d.ts +68 -68
  13. package/dist/commonjs/commands/query.js +157 -157
  14. package/dist/commonjs/commands/update.d.ts +29 -29
  15. package/dist/commonjs/commands/update.js +50 -50
  16. package/dist/commonjs/config/app.config.d.ts +6 -6
  17. package/dist/commonjs/config/app.config.js +7 -7
  18. package/dist/commonjs/config/error.config.d.ts +3 -3
  19. package/dist/commonjs/config/error.config.js +15 -15
  20. package/dist/commonjs/const/code.d.ts +30 -30
  21. package/dist/commonjs/const/code.js +32 -32
  22. package/dist/commonjs/constant.d.ts +51 -51
  23. package/dist/commonjs/constant.js +74 -74
  24. package/dist/commonjs/document.d.ts +11 -11
  25. package/dist/commonjs/document.js +252 -263
  26. package/dist/commonjs/geo/index.d.ts +6 -6
  27. package/dist/commonjs/geo/index.js +11 -11
  28. package/dist/commonjs/geo/interface.d.ts +24 -24
  29. package/dist/commonjs/geo/interface.js +2 -2
  30. package/dist/commonjs/geo/lineString.d.ts +19 -19
  31. package/dist/commonjs/geo/lineString.js +85 -85
  32. package/dist/commonjs/geo/multiLineString.d.ts +18 -18
  33. package/dist/commonjs/geo/multiLineString.js +94 -94
  34. package/dist/commonjs/geo/multiPoint.d.ts +18 -18
  35. package/dist/commonjs/geo/multiPoint.js +78 -78
  36. package/dist/commonjs/geo/multiPolygon.d.ts +18 -18
  37. package/dist/commonjs/geo/multiPolygon.js +121 -121
  38. package/dist/commonjs/geo/point.d.ts +19 -19
  39. package/dist/commonjs/geo/point.js +49 -49
  40. package/dist/commonjs/geo/polygon.d.ts +19 -19
  41. package/dist/commonjs/geo/polygon.js +108 -108
  42. package/dist/commonjs/helper/symbol.d.ts +14 -14
  43. package/dist/commonjs/helper/symbol.js +19 -19
  44. package/dist/commonjs/index.d.ts +33 -32
  45. package/dist/commonjs/index.js +46 -46
  46. package/dist/commonjs/lib/util.d.ts +1 -1
  47. package/dist/commonjs/lib/util.js +25 -25
  48. package/dist/commonjs/operator-map.d.ts +4 -4
  49. package/dist/commonjs/operator-map.js +23 -23
  50. package/dist/commonjs/query.d.ts +22 -22
  51. package/dist/commonjs/query.js +251 -262
  52. package/dist/commonjs/realtime/error.d.ts +7 -7
  53. package/dist/commonjs/realtime/error.js +11 -27
  54. package/dist/commonjs/realtime/listener.d.ts +14 -14
  55. package/dist/commonjs/realtime/listener.js +17 -18
  56. package/dist/commonjs/realtime/message.d.ts +3 -3
  57. package/dist/commonjs/realtime/message.js +10 -11
  58. package/dist/commonjs/realtime/snapshot.d.ts +16 -16
  59. package/dist/commonjs/realtime/snapshot.js +42 -43
  60. package/dist/commonjs/realtime/virtual-websocket-client.d.ts +63 -63
  61. package/dist/commonjs/realtime/virtual-websocket-client.js +736 -990
  62. package/dist/commonjs/realtime/websocket-client.d.ts +78 -78
  63. package/dist/commonjs/realtime/websocket-client.js +567 -788
  64. package/dist/commonjs/realtime/ws-event.d.ts +126 -126
  65. package/dist/commonjs/realtime/ws-event.js +139 -139
  66. package/dist/commonjs/regexp/index.d.ts +14 -14
  67. package/dist/commonjs/regexp/index.js +32 -32
  68. package/dist/commonjs/serializer/common.d.ts +11 -11
  69. package/dist/commonjs/serializer/common.js +121 -121
  70. package/dist/commonjs/serializer/datatype.d.ts +7 -7
  71. package/dist/commonjs/serializer/datatype.js +126 -126
  72. package/dist/commonjs/serializer/query.d.ts +7 -7
  73. package/dist/commonjs/serializer/query.js +231 -231
  74. package/dist/commonjs/serializer/update.d.ts +15 -15
  75. package/dist/commonjs/serializer/update.js +141 -141
  76. package/dist/commonjs/serverDate/index.d.ts +13 -13
  77. package/dist/commonjs/serverDate/index.js +29 -29
  78. package/dist/commonjs/transaction/collection.d.ts +7 -7
  79. package/dist/commonjs/transaction/collection.js +46 -46
  80. package/dist/commonjs/transaction/document.d.ts +27 -27
  81. package/dist/commonjs/transaction/document.js +205 -205
  82. package/dist/commonjs/transaction/index.d.ts +30 -30
  83. package/dist/commonjs/transaction/index.js +214 -214
  84. package/dist/commonjs/transaction/query.d.ts +5 -5
  85. package/dist/commonjs/transaction/query.js +10 -10
  86. package/dist/commonjs/transaction.d.ts +42 -42
  87. package/dist/commonjs/transaction.js +126 -126
  88. package/dist/commonjs/typings/index.d.ts +40 -40
  89. package/dist/commonjs/typings/index.js +2 -2
  90. package/dist/commonjs/typings/realtime.d.ts +219 -219
  91. package/dist/commonjs/typings/realtime.js +2 -2
  92. package/dist/commonjs/util.d.ts +9 -9
  93. package/dist/commonjs/util.js +144 -144
  94. package/dist/commonjs/utils/error.d.ts +37 -37
  95. package/dist/commonjs/utils/error.js +85 -85
  96. package/dist/commonjs/utils/symbol.d.ts +8 -8
  97. package/dist/commonjs/utils/symbol.js +57 -57
  98. package/dist/commonjs/utils/type.d.ts +13 -13
  99. package/dist/commonjs/utils/type.js +22 -22
  100. package/dist/commonjs/utils/utils.d.ts +4 -2
  101. package/dist/commonjs/utils/utils.js +36 -14
  102. package/dist/commonjs/validate.d.ts +1 -1
  103. package/dist/commonjs/validate.js +59 -59
  104. package/dist/esm/ObjectId/index.d.ts +11 -0
  105. package/dist/esm/ObjectId/index.js +17 -0
  106. package/dist/esm/aggregate.d.ts +29 -29
  107. package/dist/esm/aggregate.js +154 -144
  108. package/dist/esm/collection.d.ts +9 -9
  109. package/dist/esm/collection.js +44 -44
  110. package/dist/esm/command.d.ts +175 -175
  111. package/dist/esm/command.js +296 -296
  112. package/dist/esm/commands/logic.d.ts +24 -24
  113. package/dist/esm/commands/logic.js +84 -84
  114. package/dist/esm/commands/query.d.ts +68 -68
  115. package/dist/esm/commands/query.js +152 -152
  116. package/dist/esm/commands/update.d.ts +29 -29
  117. package/dist/esm/commands/update.js +46 -46
  118. package/dist/esm/config/app.config.d.ts +6 -6
  119. package/dist/esm/config/app.config.js +5 -5
  120. package/dist/esm/config/error.config.d.ts +3 -3
  121. package/dist/esm/config/error.config.js +13 -13
  122. package/dist/esm/const/code.d.ts +30 -30
  123. package/dist/esm/const/code.js +30 -30
  124. package/dist/esm/constant.d.ts +51 -51
  125. package/dist/esm/constant.js +65 -65
  126. package/dist/esm/document.d.ts +11 -11
  127. package/dist/esm/document.js +250 -261
  128. package/dist/esm/geo/index.d.ts +6 -6
  129. package/dist/esm/geo/index.js +6 -6
  130. package/dist/esm/geo/interface.d.ts +24 -24
  131. package/dist/esm/geo/lineString.d.ts +19 -19
  132. package/dist/esm/geo/lineString.js +83 -83
  133. package/dist/esm/geo/multiLineString.d.ts +18 -18
  134. package/dist/esm/geo/multiLineString.js +92 -92
  135. package/dist/esm/geo/multiPoint.d.ts +18 -18
  136. package/dist/esm/geo/multiPoint.js +76 -76
  137. package/dist/esm/geo/multiPolygon.d.ts +18 -18
  138. package/dist/esm/geo/multiPolygon.js +119 -119
  139. package/dist/esm/geo/point.d.ts +19 -19
  140. package/dist/esm/geo/point.js +47 -47
  141. package/dist/esm/geo/polygon.d.ts +19 -19
  142. package/dist/esm/geo/polygon.js +106 -106
  143. package/dist/esm/helper/symbol.d.ts +14 -14
  144. package/dist/esm/helper/symbol.js +14 -14
  145. package/dist/esm/index.d.ts +33 -32
  146. package/dist/esm/index.js +41 -41
  147. package/dist/esm/lib/util.d.ts +1 -1
  148. package/dist/esm/lib/util.js +23 -23
  149. package/dist/esm/operator-map.d.ts +4 -4
  150. package/dist/esm/operator-map.js +20 -20
  151. package/dist/esm/query.d.ts +22 -22
  152. package/dist/esm/query.js +249 -260
  153. package/dist/esm/realtime/error.d.ts +7 -7
  154. package/dist/esm/realtime/error.js +8 -25
  155. package/dist/esm/realtime/listener.d.ts +14 -14
  156. package/dist/esm/realtime/listener.js +14 -16
  157. package/dist/esm/realtime/message.d.ts +3 -3
  158. package/dist/esm/realtime/message.js +6 -7
  159. package/dist/esm/realtime/snapshot.d.ts +16 -16
  160. package/dist/esm/realtime/snapshot.js +39 -41
  161. package/dist/esm/realtime/virtual-websocket-client.d.ts +63 -63
  162. package/dist/esm/realtime/virtual-websocket-client.js +733 -988
  163. package/dist/esm/realtime/websocket-client.d.ts +78 -78
  164. package/dist/esm/realtime/websocket-client.js +564 -786
  165. package/dist/esm/realtime/ws-event.d.ts +126 -126
  166. package/dist/esm/realtime/ws-event.js +137 -137
  167. package/dist/esm/regexp/index.d.ts +14 -14
  168. package/dist/esm/regexp/index.js +29 -29
  169. package/dist/esm/serializer/common.d.ts +11 -11
  170. package/dist/esm/serializer/common.js +113 -113
  171. package/dist/esm/serializer/datatype.d.ts +7 -7
  172. package/dist/esm/serializer/datatype.js +122 -122
  173. package/dist/esm/serializer/query.d.ts +7 -7
  174. package/dist/esm/serializer/query.js +229 -229
  175. package/dist/esm/serializer/update.d.ts +15 -15
  176. package/dist/esm/serializer/update.js +139 -139
  177. package/dist/esm/serverDate/index.d.ts +13 -13
  178. package/dist/esm/serverDate/index.js +26 -26
  179. package/dist/esm/transaction/collection.d.ts +7 -7
  180. package/dist/esm/transaction/collection.js +44 -44
  181. package/dist/esm/transaction/document.d.ts +27 -27
  182. package/dist/esm/transaction/document.js +203 -203
  183. package/dist/esm/transaction/index.d.ts +30 -30
  184. package/dist/esm/transaction/index.js +210 -210
  185. package/dist/esm/transaction/query.d.ts +5 -5
  186. package/dist/esm/transaction/query.js +8 -8
  187. package/dist/esm/transaction.d.ts +42 -42
  188. package/dist/esm/transaction.js +121 -121
  189. package/dist/esm/typings/index.d.ts +40 -40
  190. package/dist/esm/typings/realtime.d.ts +219 -219
  191. package/dist/esm/util.d.ts +9 -9
  192. package/dist/esm/util.js +142 -142
  193. package/dist/esm/utils/error.d.ts +37 -37
  194. package/dist/esm/utils/error.js +82 -82
  195. package/dist/esm/utils/symbol.d.ts +8 -8
  196. package/dist/esm/utils/symbol.js +55 -55
  197. package/dist/esm/utils/type.d.ts +13 -13
  198. package/dist/esm/utils/type.js +20 -20
  199. package/dist/esm/utils/utils.d.ts +4 -2
  200. package/dist/esm/utils/utils.js +33 -12
  201. package/dist/esm/validate.d.ts +1 -1
  202. package/dist/esm/validate.js +57 -57
  203. package/package.json +4 -1
  204. package/src/aggregate.ts +11 -0
  205. package/src/document.ts +3 -15
  206. package/src/index.ts +2 -0
  207. package/src/query.ts +4 -16
  208. package/src/utils/utils.ts +28 -0
  209. package/.DS_Store +0 -0
  210. package/src/.DS_Store +0 -0
  211. package/src/realtime/error.ts +0 -19
  212. package/src/realtime/listener.ts +0 -35
  213. package/src/realtime/message.ts +0 -14
  214. package/src/realtime/snapshot.ts +0 -60
  215. package/src/realtime/virtual-websocket-client.ts +0 -1195
  216. package/src/realtime/websocket-client.ts +0 -995
  217. package/src/realtime/ws-event.ts +0 -163
  218. package/src/regexp/.DS_Store +0 -0
@@ -1,990 +1,736 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
- function verb(n) { return function (v) { return step([n, v]); }; }
15
- function step(op) {
16
- if (f) throw new TypeError("Generator is already executing.");
17
- while (_) try {
18
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
- if (y = 0, t) op = [op[0] & 2, t.value];
20
- switch (op[0]) {
21
- case 0: case 1: t = op; break;
22
- case 4: _.label++; return { value: op[1], done: false };
23
- case 5: _.label++; y = op[1]; op = [0]; continue;
24
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
- default:
26
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
- if (t[2]) _.ops.pop();
31
- _.trys.pop(); continue;
32
- }
33
- op = body.call(thisArg, _);
34
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
- }
37
- };
38
- var __values = (this && this.__values) || function(o) {
39
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
40
- if (m) return m.call(o);
41
- if (o && typeof o.length === "number") return {
42
- next: function () {
43
- if (o && i >= o.length) o = void 0;
44
- return { value: o && o[i++], done: !o };
45
- }
46
- };
47
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
48
- };
49
- var __read = (this && this.__read) || function (o, n) {
50
- var m = typeof Symbol === "function" && o[Symbol.iterator];
51
- if (!m) return o;
52
- var i = m.call(o), r, ar = [], e;
53
- try {
54
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
55
- }
56
- catch (error) { e = { error: error }; }
57
- finally {
58
- try {
59
- if (r && !r.done && (m = i["return"])) m.call(i);
60
- }
61
- finally { if (e) throw e.error; }
62
- }
63
- return ar;
64
- };
65
- var __spread = (this && this.__spread) || function () {
66
- for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
67
- return ar;
68
- };
69
- Object.defineProperty(exports, "__esModule", { value: true });
70
- var lodash_set_1 = require("lodash.set");
71
- var lodash_unset_1 = require("lodash.unset");
72
- var lodash_clonedeep_1 = require("lodash.clonedeep");
73
- var message_1 = require("./message");
74
- var error_1 = require("../utils/error");
75
- var error_config_1 = require("../config/error.config");
76
- var utils_1 = require("../utils/utils");
77
- var listener_1 = require("./listener");
78
- var snapshot_1 = require("./snapshot");
79
- var error_2 = require("./error");
80
- var WATCH_STATUS;
81
- (function (WATCH_STATUS) {
82
- WATCH_STATUS["LOGGINGIN"] = "LOGGINGIN";
83
- WATCH_STATUS["INITING"] = "INITING";
84
- WATCH_STATUS["REBUILDING"] = "REBUILDING";
85
- WATCH_STATUS["ACTIVE"] = "ACTIVE";
86
- WATCH_STATUS["ERRORED"] = "ERRORED";
87
- WATCH_STATUS["CLOSING"] = "CLOSING";
88
- WATCH_STATUS["CLOSED"] = "CLOSED";
89
- WATCH_STATUS["PAUSED"] = "PAUSED";
90
- WATCH_STATUS["RESUMING"] = "RESUMING";
91
- })(WATCH_STATUS || (WATCH_STATUS = {}));
92
- var DEFAULT_WAIT_TIME_ON_UNKNOWN_ERROR = 100;
93
- var DEFAULT_MAX_AUTO_RETRY_ON_ERROR = 2;
94
- var DEFAULT_MAX_SEND_ACK_AUTO_RETRY_ON_ERROR = 2;
95
- var DEFAULT_SEND_ACK_DEBOUNCE_TIMEOUT = 10 * 1000;
96
- var DEFAULT_INIT_WATCH_TIMEOUT = 10 * 1000;
97
- var DEFAULT_REBUILD_WATCH_TIMEOUT = 10 * 1000;
98
- var VirtualWebSocketClient = (function () {
99
- function VirtualWebSocketClient(options) {
100
- var _this = this;
101
- this.watchStatus = WATCH_STATUS.INITING;
102
- this._login = function (envId, refresh) { return __awaiter(_this, void 0, void 0, function () {
103
- var loginResult;
104
- return __generator(this, function (_a) {
105
- switch (_a.label) {
106
- case 0:
107
- this.watchStatus = WATCH_STATUS.LOGGINGIN;
108
- return [4, this.login(envId, refresh)];
109
- case 1:
110
- loginResult = _a.sent();
111
- if (!this.envId) {
112
- this.envId = loginResult.envId;
113
- }
114
- return [2, loginResult];
115
- }
116
- });
117
- }); };
118
- this.initWatch = function (forceRefreshLogin) { return __awaiter(_this, void 0, void 0, function () {
119
- var success;
120
- var _this = this;
121
- return __generator(this, function (_a) {
122
- switch (_a.label) {
123
- case 0:
124
- if (this._initWatchPromise) {
125
- return [2, this._initWatchPromise];
126
- }
127
- this._initWatchPromise = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
128
- var envId, initWatchMsg, initEventMsg, _a, events, currEvent, events_1, events_1_1, e, snapshot, e_1;
129
- var e_2, _b;
130
- return __generator(this, function (_c) {
131
- switch (_c.label) {
132
- case 0:
133
- _c.trys.push([0, 3, , 4]);
134
- if (this.watchStatus === WATCH_STATUS.PAUSED) {
135
- console.log('[realtime] initWatch cancelled on pause');
136
- return [2, resolve()];
137
- }
138
- return [4, this._login(this.envId, forceRefreshLogin)];
139
- case 1:
140
- envId = (_c.sent()).envId;
141
- if (this.watchStatus === WATCH_STATUS.PAUSED) {
142
- console.log('[realtime] initWatch cancelled on pause');
143
- return [2, resolve()];
144
- }
145
- this.watchStatus = WATCH_STATUS.INITING;
146
- initWatchMsg = {
147
- watchId: this.watchId,
148
- requestId: message_1.genRequestId(),
149
- msgType: 'INIT_WATCH',
150
- msgData: {
151
- envId: envId,
152
- collName: this.collectionName,
153
- query: this.query,
154
- limit: this.limit,
155
- orderBy: this.orderBy
156
- }
157
- };
158
- return [4, this.send({
159
- msg: initWatchMsg,
160
- waitResponse: true,
161
- skipOnMessage: true,
162
- timeout: DEFAULT_INIT_WATCH_TIMEOUT
163
- })];
164
- case 2:
165
- initEventMsg = _c.sent();
166
- _a = initEventMsg.msgData, events = _a.events, currEvent = _a.currEvent;
167
- this.sessionInfo = {
168
- queryID: initEventMsg.msgData.queryID,
169
- currentEventId: currEvent - 1,
170
- currentDocs: []
171
- };
172
- if (events.length > 0) {
173
- try {
174
- for (events_1 = __values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) {
175
- e = events_1_1.value;
176
- e.ID = currEvent;
177
- }
178
- }
179
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
180
- finally {
181
- try {
182
- if (events_1_1 && !events_1_1.done && (_b = events_1.return)) _b.call(events_1);
183
- }
184
- finally { if (e_2) throw e_2.error; }
185
- }
186
- this.handleServerEvents(initEventMsg);
187
- }
188
- else {
189
- this.sessionInfo.currentEventId = currEvent;
190
- snapshot = new snapshot_1.Snapshot({
191
- id: currEvent,
192
- docChanges: [],
193
- docs: [],
194
- type: 'init'
195
- });
196
- this.listener.onChange(snapshot);
197
- this.scheduleSendACK();
198
- }
199
- this.onWatchStart(this, this.sessionInfo.queryID);
200
- this.watchStatus = WATCH_STATUS.ACTIVE;
201
- this._availableRetries.INIT_WATCH = DEFAULT_MAX_AUTO_RETRY_ON_ERROR;
202
- resolve();
203
- return [3, 4];
204
- case 3:
205
- e_1 = _c.sent();
206
- this.handleWatchEstablishmentError(e_1, {
207
- operationName: 'INIT_WATCH',
208
- resolve: resolve,
209
- reject: reject
210
- });
211
- return [3, 4];
212
- case 4: return [2];
213
- }
214
- });
215
- }); });
216
- success = false;
217
- _a.label = 1;
218
- case 1:
219
- _a.trys.push([1, , 3, 4]);
220
- return [4, this._initWatchPromise];
221
- case 2:
222
- _a.sent();
223
- success = true;
224
- return [3, 4];
225
- case 3:
226
- this._initWatchPromise = undefined;
227
- return [7];
228
- case 4:
229
- console.log("[realtime] initWatch " + (success ? 'success' : 'fail'));
230
- return [2];
231
- }
232
- });
233
- }); };
234
- this.rebuildWatch = function (forceRefreshLogin) { return __awaiter(_this, void 0, void 0, function () {
235
- var success;
236
- var _this = this;
237
- return __generator(this, function (_a) {
238
- switch (_a.label) {
239
- case 0:
240
- if (this._rebuildWatchPromise) {
241
- return [2, this._rebuildWatchPromise];
242
- }
243
- this._rebuildWatchPromise = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
244
- var envId, rebuildWatchMsg, nextEventMsg, e_3;
245
- return __generator(this, function (_a) {
246
- switch (_a.label) {
247
- case 0:
248
- _a.trys.push([0, 3, , 4]);
249
- if (this.watchStatus === WATCH_STATUS.PAUSED) {
250
- console.log('[realtime] rebuildWatch cancelled on pause');
251
- return [2, resolve()];
252
- }
253
- return [4, this._login(this.envId, forceRefreshLogin)];
254
- case 1:
255
- envId = (_a.sent()).envId;
256
- if (!this.sessionInfo) {
257
- throw new Error('can not rebuildWatch without a successful initWatch (lack of sessionInfo)');
258
- }
259
- if (this.watchStatus === WATCH_STATUS.PAUSED) {
260
- console.log('[realtime] rebuildWatch cancelled on pause');
261
- return [2, resolve()];
262
- }
263
- this.watchStatus = WATCH_STATUS.REBUILDING;
264
- rebuildWatchMsg = {
265
- watchId: this.watchId,
266
- requestId: message_1.genRequestId(),
267
- msgType: 'REBUILD_WATCH',
268
- msgData: {
269
- envId: envId,
270
- collName: this.collectionName,
271
- queryID: this.sessionInfo.queryID,
272
- eventID: this.sessionInfo.currentEventId
273
- }
274
- };
275
- return [4, this.send({
276
- msg: rebuildWatchMsg,
277
- waitResponse: true,
278
- skipOnMessage: false,
279
- timeout: DEFAULT_REBUILD_WATCH_TIMEOUT
280
- })];
281
- case 2:
282
- nextEventMsg = _a.sent();
283
- this.handleServerEvents(nextEventMsg);
284
- this.watchStatus = WATCH_STATUS.ACTIVE;
285
- this._availableRetries.REBUILD_WATCH = DEFAULT_MAX_AUTO_RETRY_ON_ERROR;
286
- resolve();
287
- return [3, 4];
288
- case 3:
289
- e_3 = _a.sent();
290
- this.handleWatchEstablishmentError(e_3, {
291
- operationName: 'REBUILD_WATCH',
292
- resolve: resolve,
293
- reject: reject
294
- });
295
- return [3, 4];
296
- case 4: return [2];
297
- }
298
- });
299
- }); });
300
- success = false;
301
- _a.label = 1;
302
- case 1:
303
- _a.trys.push([1, , 3, 4]);
304
- return [4, this._rebuildWatchPromise];
305
- case 2:
306
- _a.sent();
307
- success = true;
308
- return [3, 4];
309
- case 3:
310
- this._rebuildWatchPromise = undefined;
311
- return [7];
312
- case 4:
313
- console.log("[realtime] rebuildWatch " + (success ? 'success' : 'fail'));
314
- return [2];
315
- }
316
- });
317
- }); };
318
- this.handleWatchEstablishmentError = function (e, options) { return __awaiter(_this, void 0, void 0, function () {
319
- var isInitWatch, abortWatch, retry;
320
- var _this = this;
321
- return __generator(this, function (_a) {
322
- isInitWatch = options.operationName === 'INIT_WATCH';
323
- abortWatch = function () {
324
- _this.closeWithError(new error_1.CloudSDKError({
325
- errCode: isInitWatch
326
- ? error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_INIT_WATCH_FAIL
327
- : error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_REBUILD_WATCH_FAIL,
328
- errMsg: e
329
- }));
330
- options.reject(e);
331
- };
332
- retry = function (refreshLogin) {
333
- if (_this.useRetryTicket(options.operationName)) {
334
- if (isInitWatch) {
335
- _this._initWatchPromise = undefined;
336
- options.resolve(_this.initWatch(refreshLogin));
337
- }
338
- else {
339
- _this._rebuildWatchPromise = undefined;
340
- options.resolve(_this.rebuildWatch(refreshLogin));
341
- }
342
- }
343
- else {
344
- abortWatch();
345
- }
346
- };
347
- this.handleCommonError(e, {
348
- onSignError: function () { return retry(true); },
349
- onTimeoutError: function () { return retry(false); },
350
- onNotRetryableError: abortWatch,
351
- onCancelledError: options.reject,
352
- onUnknownError: function () { return __awaiter(_this, void 0, void 0, function () {
353
- var onWSDisconnected, e_4;
354
- var _this = this;
355
- return __generator(this, function (_a) {
356
- switch (_a.label) {
357
- case 0:
358
- _a.trys.push([0, 8, , 9]);
359
- onWSDisconnected = function () { return __awaiter(_this, void 0, void 0, function () {
360
- return __generator(this, function (_a) {
361
- switch (_a.label) {
362
- case 0:
363
- this.pause();
364
- return [4, this.onceWSConnected()];
365
- case 1:
366
- _a.sent();
367
- retry(true);
368
- return [2];
369
- }
370
- });
371
- }); };
372
- if (!!this.isWSConnected()) return [3, 2];
373
- return [4, onWSDisconnected()];
374
- case 1:
375
- _a.sent();
376
- return [3, 7];
377
- case 2: return [4, utils_1.sleep(DEFAULT_WAIT_TIME_ON_UNKNOWN_ERROR)];
378
- case 3:
379
- _a.sent();
380
- if (!(this.watchStatus === WATCH_STATUS.PAUSED)) return [3, 4];
381
- options.reject(new error_1.CancelledError(options.operationName + " cancelled due to pause after unknownError"));
382
- return [3, 7];
383
- case 4:
384
- if (!!this.isWSConnected()) return [3, 6];
385
- return [4, onWSDisconnected()];
386
- case 5:
387
- _a.sent();
388
- return [3, 7];
389
- case 6:
390
- retry(false);
391
- _a.label = 7;
392
- case 7: return [3, 9];
393
- case 8:
394
- e_4 = _a.sent();
395
- retry(true);
396
- return [3, 9];
397
- case 9: return [2];
398
- }
399
- });
400
- }); }
401
- });
402
- return [2];
403
- });
404
- }); };
405
- this.closeWatch = function () { return __awaiter(_this, void 0, void 0, function () {
406
- var queryId, closeWatchMsg, e_5;
407
- return __generator(this, function (_a) {
408
- switch (_a.label) {
409
- case 0:
410
- queryId = this.sessionInfo ? this.sessionInfo.queryID : '';
411
- if (this.watchStatus !== WATCH_STATUS.ACTIVE) {
412
- this.watchStatus = WATCH_STATUS.CLOSED;
413
- this.onWatchClose(this, queryId);
414
- return [2];
415
- }
416
- _a.label = 1;
417
- case 1:
418
- _a.trys.push([1, 3, 4, 5]);
419
- this.watchStatus = WATCH_STATUS.CLOSING;
420
- closeWatchMsg = {
421
- watchId: this.watchId,
422
- requestId: message_1.genRequestId(),
423
- msgType: 'CLOSE_WATCH',
424
- msgData: null
425
- };
426
- return [4, this.send({
427
- msg: closeWatchMsg
428
- })];
429
- case 2:
430
- _a.sent();
431
- this.sessionInfo = undefined;
432
- this.watchStatus = WATCH_STATUS.CLOSED;
433
- return [3, 5];
434
- case 3:
435
- e_5 = _a.sent();
436
- this.closeWithError(new error_1.CloudSDKError({
437
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_CLOSE_WATCH_FAIL,
438
- errMsg: e_5
439
- }));
440
- return [3, 5];
441
- case 4:
442
- this.onWatchClose(this, queryId);
443
- return [7];
444
- case 5: return [2];
445
- }
446
- });
447
- }); };
448
- this.scheduleSendACK = function () {
449
- _this.clearACKSchedule();
450
- _this._ackTimeoutId = setTimeout(function () {
451
- if (_this._waitExpectedTimeoutId) {
452
- _this.scheduleSendACK();
453
- }
454
- else {
455
- _this.sendACK();
456
- }
457
- }, DEFAULT_SEND_ACK_DEBOUNCE_TIMEOUT);
458
- };
459
- this.clearACKSchedule = function () {
460
- if (_this._ackTimeoutId) {
461
- clearTimeout(_this._ackTimeoutId);
462
- }
463
- };
464
- this.sendACK = function () { return __awaiter(_this, void 0, void 0, function () {
465
- var ackMsg, e_6, msg;
466
- return __generator(this, function (_a) {
467
- switch (_a.label) {
468
- case 0:
469
- _a.trys.push([0, 2, , 3]);
470
- if (this.watchStatus !== WATCH_STATUS.ACTIVE) {
471
- this.scheduleSendACK();
472
- return [2];
473
- }
474
- if (!this.sessionInfo) {
475
- console.warn('[realtime listener] can not send ack without a successful initWatch (lack of sessionInfo)');
476
- return [2];
477
- }
478
- ackMsg = {
479
- watchId: this.watchId,
480
- requestId: message_1.genRequestId(),
481
- msgType: 'CHECK_LAST',
482
- msgData: {
483
- queryID: this.sessionInfo.queryID,
484
- eventID: this.sessionInfo.currentEventId
485
- }
486
- };
487
- return [4, this.send({
488
- msg: ackMsg
489
- })];
490
- case 1:
491
- _a.sent();
492
- this.scheduleSendACK();
493
- return [3, 3];
494
- case 2:
495
- e_6 = _a.sent();
496
- if (error_2.isRealtimeErrorMessageError(e_6)) {
497
- msg = e_6.payload;
498
- switch (msg.msgData.code) {
499
- case 'CHECK_LOGIN_FAILED':
500
- case 'SIGN_EXPIRED_ERROR':
501
- case 'SIGN_INVALID_ERROR':
502
- case 'SIGN_PARAM_INVALID': {
503
- this.rebuildWatch();
504
- return [2];
505
- }
506
- case 'QUERYID_INVALID_ERROR':
507
- case 'SYS_ERR':
508
- case 'INVALIID_ENV':
509
- case 'COLLECTION_PERMISSION_DENIED': {
510
- this.closeWithError(new error_1.CloudSDKError({
511
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_CHECK_LAST_FAIL,
512
- errMsg: msg.msgData.code
513
- }));
514
- return [2];
515
- }
516
- default: {
517
- break;
518
- }
519
- }
520
- }
521
- if (this._availableRetries.CHECK_LAST &&
522
- this._availableRetries.CHECK_LAST > 0) {
523
- this._availableRetries.CHECK_LAST--;
524
- this.scheduleSendACK();
525
- }
526
- else {
527
- this.closeWithError(new error_1.CloudSDKError({
528
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_CHECK_LAST_FAIL,
529
- errMsg: e_6
530
- }));
531
- }
532
- return [3, 3];
533
- case 3: return [2];
534
- }
535
- });
536
- }); };
537
- this.handleCommonError = function (e, options) {
538
- if (error_2.isRealtimeErrorMessageError(e)) {
539
- var msg = e.payload;
540
- switch (msg.msgData.code) {
541
- case 'CHECK_LOGIN_FAILED':
542
- case 'SIGN_EXPIRED_ERROR':
543
- case 'SIGN_INVALID_ERROR':
544
- case 'SIGN_PARAM_INVALID': {
545
- options.onSignError(e);
546
- return;
547
- }
548
- case 'QUERYID_INVALID_ERROR':
549
- case 'SYS_ERR':
550
- case 'INVALIID_ENV':
551
- case 'COLLECTION_PERMISSION_DENIED': {
552
- options.onNotRetryableError(e);
553
- return;
554
- }
555
- default: {
556
- options.onNotRetryableError(e);
557
- return;
558
- }
559
- }
560
- }
561
- else if (error_1.isTimeoutError(e)) {
562
- options.onTimeoutError(e);
563
- return;
564
- }
565
- else if (error_1.isCancelledError(e)) {
566
- options.onCancelledError(e);
567
- return;
568
- }
569
- options.onUnknownError(e);
570
- };
571
- this.watchId = "watchid_" + +new Date() + "_" + Math.random();
572
- this.envId = options.envId;
573
- this.collectionName = options.collectionName;
574
- this.query = options.query;
575
- this.limit = options.limit;
576
- this.orderBy = options.orderBy;
577
- this.send = options.send;
578
- this.login = options.login;
579
- this.isWSConnected = options.isWSConnected;
580
- this.onceWSConnected = options.onceWSConnected;
581
- this.getWaitExpectedTimeoutLength = options.getWaitExpectedTimeoutLength;
582
- this.onWatchStart = options.onWatchStart;
583
- this.onWatchClose = options.onWatchClose;
584
- this.debug = options.debug;
585
- this._availableRetries = {
586
- INIT_WATCH: DEFAULT_MAX_AUTO_RETRY_ON_ERROR,
587
- REBUILD_WATCH: DEFAULT_MAX_AUTO_RETRY_ON_ERROR,
588
- CHECK_LAST: DEFAULT_MAX_SEND_ACK_AUTO_RETRY_ON_ERROR
589
- };
590
- this.listener = new listener_1.RealtimeListener({
591
- close: this.closeWatch,
592
- onChange: options.onChange,
593
- onError: options.onError,
594
- debug: this.debug,
595
- virtualClient: this
596
- });
597
- this.initWatch();
598
- }
599
- VirtualWebSocketClient.prototype.useRetryTicket = function (operationName) {
600
- if (this._availableRetries[operationName] &&
601
- this._availableRetries[operationName] > 0) {
602
- this._availableRetries[operationName]--;
603
- console.log("[realtime] " + operationName + " use a retry ticket, now only " + this._availableRetries[operationName] + " retry left");
604
- return true;
605
- }
606
- return false;
607
- };
608
- VirtualWebSocketClient.prototype.handleServerEvents = function (msg) {
609
- return __awaiter(this, void 0, void 0, function () {
610
- var e_7;
611
- return __generator(this, function (_a) {
612
- switch (_a.label) {
613
- case 0:
614
- _a.trys.push([0, 2, , 3]);
615
- this.scheduleSendACK();
616
- return [4, this._handleServerEvents(msg)];
617
- case 1:
618
- _a.sent();
619
- this._postHandleServerEventsValidityCheck(msg);
620
- return [3, 3];
621
- case 2:
622
- e_7 = _a.sent();
623
- console.error('[realtime listener] internal non-fatal error: handle server events failed with error: ', e_7);
624
- throw e_7;
625
- case 3: return [2];
626
- }
627
- });
628
- });
629
- };
630
- VirtualWebSocketClient.prototype._handleServerEvents = function (msg) {
631
- return __awaiter(this, void 0, void 0, function () {
632
- var requestId, events, msgType, sessionInfo, allChangeEvents, docs, initEncountered, _loop_1, this_1, i, len, state_1;
633
- return __generator(this, function (_a) {
634
- switch (_a.label) {
635
- case 0:
636
- requestId = msg.requestId;
637
- events = msg.msgData.events;
638
- msgType = msg.msgType;
639
- if (!events.length || !this.sessionInfo) {
640
- return [2];
641
- }
642
- sessionInfo = this.sessionInfo;
643
- try {
644
- allChangeEvents = events.map(getPublicEvent);
645
- }
646
- catch (e) {
647
- this.closeWithError(new error_1.CloudSDKError({
648
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_RECEIVE_INVALID_SERVER_DATA,
649
- errMsg: e
650
- }));
651
- return [2];
652
- }
653
- docs = __spread(sessionInfo.currentDocs);
654
- initEncountered = false;
655
- _loop_1 = function (i, len) {
656
- var change, localDoc, doc, fieldPath, _a, _b, fieldPath, err, err, doc, doc, err, ind, ind, docsSnapshot, docChanges, snapshot;
657
- var e_8, _c;
658
- return __generator(this, function (_d) {
659
- switch (_d.label) {
660
- case 0:
661
- change = allChangeEvents[i];
662
- if (!(sessionInfo.currentEventId >= change.id)) return [3, 1];
663
- if (!allChangeEvents[i - 1] || change.id > allChangeEvents[i - 1].id) {
664
- console.warn("[realtime] duplicate event received, cur " + sessionInfo.currentEventId + " but got " + change.id);
665
- }
666
- else {
667
- console.error("[realtime listener] server non-fatal error: events out of order (the latter event's id is smaller than that of the former) (requestId " + requestId + ")");
668
- }
669
- return [2, "continue"];
670
- case 1:
671
- if (!(sessionInfo.currentEventId === change.id - 1)) return [3, 2];
672
- switch (change.dataType) {
673
- case 'update': {
674
- if (!change.doc) {
675
- switch (change.queueType) {
676
- case 'update':
677
- case 'dequeue': {
678
- localDoc = docs.find(function (doc) { return doc._id === change.docId; });
679
- if (localDoc) {
680
- doc = lodash_clonedeep_1.default(localDoc);
681
- if (change.updatedFields) {
682
- for (fieldPath in change.updatedFields) {
683
- lodash_set_1.default(doc, fieldPath, change.updatedFields[fieldPath]);
684
- }
685
- }
686
- if (change.removedFields) {
687
- try {
688
- for (_a = (e_8 = void 0, __values(change.removedFields)), _b = _a.next(); !_b.done; _b = _a.next()) {
689
- fieldPath = _b.value;
690
- lodash_unset_1.default(doc, fieldPath);
691
- }
692
- }
693
- catch (e_8_1) { e_8 = { error: e_8_1 }; }
694
- finally {
695
- try {
696
- if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
697
- }
698
- finally { if (e_8) throw e_8.error; }
699
- }
700
- }
701
- change.doc = doc;
702
- }
703
- else {
704
- console.error('[realtime listener] internal non-fatal server error: unexpected update dataType event where no doc is associated.');
705
- }
706
- break;
707
- }
708
- case 'enqueue': {
709
- err = new error_1.CloudSDKError({
710
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_UNEXPECTED_FATAL_ERROR,
711
- errMsg: "HandleServerEvents: full doc is not provided with dataType=\"update\" and queueType=\"enqueue\" (requestId " + msg.requestId + ")"
712
- });
713
- this_1.closeWithError(err);
714
- throw err;
715
- }
716
- default: {
717
- break;
718
- }
719
- }
720
- }
721
- break;
722
- }
723
- case 'replace': {
724
- if (!change.doc) {
725
- err = new error_1.CloudSDKError({
726
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_UNEXPECTED_FATAL_ERROR,
727
- errMsg: "HandleServerEvents: full doc is not provided with dataType=\"replace\" (requestId " + msg.requestId + ")"
728
- });
729
- this_1.closeWithError(err);
730
- throw err;
731
- }
732
- break;
733
- }
734
- case 'remove': {
735
- doc = docs.find(function (doc) { return doc._id === change.docId; });
736
- if (doc) {
737
- change.doc = doc;
738
- }
739
- else {
740
- console.error('[realtime listener] internal non-fatal server error: unexpected remove event where no doc is associated.');
741
- }
742
- break;
743
- }
744
- case 'limit': {
745
- if (!change.doc) {
746
- switch (change.queueType) {
747
- case 'dequeue': {
748
- doc = docs.find(function (doc) { return doc._id === change.docId; });
749
- if (doc) {
750
- change.doc = doc;
751
- }
752
- else {
753
- console.error('[realtime listener] internal non-fatal server error: unexpected limit dataType event where no doc is associated.');
754
- }
755
- break;
756
- }
757
- case 'enqueue': {
758
- err = new error_1.CloudSDKError({
759
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_UNEXPECTED_FATAL_ERROR,
760
- errMsg: "HandleServerEvents: full doc is not provided with dataType=\"limit\" and queueType=\"enqueue\" (requestId " + msg.requestId + ")"
761
- });
762
- this_1.closeWithError(err);
763
- throw err;
764
- }
765
- default: {
766
- break;
767
- }
768
- }
769
- }
770
- break;
771
- }
772
- }
773
- switch (change.queueType) {
774
- case 'init': {
775
- if (!initEncountered) {
776
- initEncountered = true;
777
- docs = [change.doc];
778
- }
779
- else {
780
- docs.push(change.doc);
781
- }
782
- break;
783
- }
784
- case 'enqueue': {
785
- docs.push(change.doc);
786
- break;
787
- }
788
- case 'dequeue': {
789
- ind = docs.findIndex(function (doc) { return doc._id === change.docId; });
790
- if (ind > -1) {
791
- docs.splice(ind, 1);
792
- }
793
- else {
794
- console.error('[realtime listener] internal non-fatal server error: unexpected dequeue event where no doc is associated.');
795
- }
796
- break;
797
- }
798
- case 'update': {
799
- ind = docs.findIndex(function (doc) { return doc._id === change.docId; });
800
- if (ind > -1) {
801
- docs[ind] = change.doc;
802
- }
803
- else {
804
- console.error('[realtime listener] internal non-fatal server error: unexpected queueType update event where no doc is associated.');
805
- }
806
- break;
807
- }
808
- }
809
- if (i === len - 1 ||
810
- (allChangeEvents[i + 1] && allChangeEvents[i + 1].id !== change.id)) {
811
- docsSnapshot = __spread(docs);
812
- docChanges = allChangeEvents
813
- .slice(0, i + 1)
814
- .filter(function (c) { return c.id === change.id; });
815
- this_1.sessionInfo.currentEventId = change.id;
816
- this_1.sessionInfo.currentDocs = docs;
817
- snapshot = new snapshot_1.Snapshot({
818
- id: change.id,
819
- docChanges: docChanges,
820
- docs: docsSnapshot,
821
- msgType: msgType
822
- });
823
- this_1.listener.onChange(snapshot);
824
- }
825
- return [3, 4];
826
- case 2:
827
- console.warn("[realtime listener] event received is out of order, cur " + this_1.sessionInfo.currentEventId + " but got " + change.id);
828
- return [4, this_1.rebuildWatch()];
829
- case 3:
830
- _d.sent();
831
- return [2, { value: void 0 }];
832
- case 4: return [2];
833
- }
834
- });
835
- };
836
- this_1 = this;
837
- i = 0, len = allChangeEvents.length;
838
- _a.label = 1;
839
- case 1:
840
- if (!(i < len)) return [3, 4];
841
- return [5, _loop_1(i, len)];
842
- case 2:
843
- state_1 = _a.sent();
844
- if (typeof state_1 === "object")
845
- return [2, state_1.value];
846
- _a.label = 3;
847
- case 3:
848
- i++;
849
- return [3, 1];
850
- case 4: return [2];
851
- }
852
- });
853
- });
854
- };
855
- VirtualWebSocketClient.prototype._postHandleServerEventsValidityCheck = function (msg) {
856
- if (!this.sessionInfo) {
857
- console.error('[realtime listener] internal non-fatal error: sessionInfo lost after server event handling, this should never occur');
858
- return;
859
- }
860
- if (this.sessionInfo.expectEventId &&
861
- this.sessionInfo.currentEventId >= this.sessionInfo.expectEventId) {
862
- this.clearWaitExpectedEvent();
863
- }
864
- if (this.sessionInfo.currentEventId < msg.msgData.currEvent) {
865
- console.warn('[realtime listener] internal non-fatal error: client eventId does not match with server event id after server event handling');
866
- return;
867
- }
868
- };
869
- VirtualWebSocketClient.prototype.clearWaitExpectedEvent = function () {
870
- if (this._waitExpectedTimeoutId) {
871
- clearTimeout(this._waitExpectedTimeoutId);
872
- this._waitExpectedTimeoutId = undefined;
873
- }
874
- };
875
- VirtualWebSocketClient.prototype.onMessage = function (msg) {
876
- var _this = this;
877
- switch (this.watchStatus) {
878
- case WATCH_STATUS.PAUSED: {
879
- if (msg.msgType !== 'ERROR') {
880
- return;
881
- }
882
- break;
883
- }
884
- case WATCH_STATUS.LOGGINGIN:
885
- case WATCH_STATUS.INITING:
886
- case WATCH_STATUS.REBUILDING: {
887
- console.warn("[realtime listener] internal non-fatal error: unexpected message received while " + this.watchStatus);
888
- return;
889
- }
890
- case WATCH_STATUS.CLOSED: {
891
- console.warn('[realtime listener] internal non-fatal error: unexpected message received when the watch has closed');
892
- return;
893
- }
894
- case WATCH_STATUS.ERRORED: {
895
- console.warn('[realtime listener] internal non-fatal error: unexpected message received when the watch has ended with error');
896
- return;
897
- }
898
- }
899
- if (!this.sessionInfo) {
900
- console.warn('[realtime listener] internal non-fatal error: sessionInfo not found while message is received.');
901
- return;
902
- }
903
- this.scheduleSendACK();
904
- switch (msg.msgType) {
905
- case 'NEXT_EVENT': {
906
- console.warn("nextevent " + msg.msgData.currEvent + " ignored", msg);
907
- this.handleServerEvents(msg);
908
- break;
909
- }
910
- case 'CHECK_EVENT': {
911
- if (this.sessionInfo.currentEventId < msg.msgData.currEvent) {
912
- this.sessionInfo.expectEventId = msg.msgData.currEvent;
913
- this.clearWaitExpectedEvent();
914
- this._waitExpectedTimeoutId = setTimeout(function () {
915
- _this.rebuildWatch();
916
- }, this.getWaitExpectedTimeoutLength());
917
- console.log("[realtime] waitExpectedTimeoutLength " + this.getWaitExpectedTimeoutLength());
918
- }
919
- break;
920
- }
921
- case 'ERROR': {
922
- this.closeWithError(new error_1.CloudSDKError({
923
- errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_SERVER_ERROR_MSG,
924
- errMsg: msg.msgData.code + " - " + msg.msgData.message
925
- }));
926
- break;
927
- }
928
- default: {
929
- console.warn("[realtime listener] virtual client receive unexpected msg " + msg.msgType + ": ", msg);
930
- break;
931
- }
932
- }
933
- };
934
- VirtualWebSocketClient.prototype.closeWithError = function (error) {
935
- this.watchStatus = WATCH_STATUS.ERRORED;
936
- this.clearACKSchedule();
937
- this.listener.onError(error);
938
- this.onWatchClose(this, (this.sessionInfo && this.sessionInfo.queryID) || '');
939
- console.log("[realtime] client closed (" + this.collectionName + " " + this.query + ") (watchId " + this.watchId + ")");
940
- };
941
- VirtualWebSocketClient.prototype.pause = function () {
942
- this.watchStatus = WATCH_STATUS.PAUSED;
943
- console.log("[realtime] client paused (" + this.collectionName + " " + this.query + ") (watchId " + this.watchId + ")");
944
- };
945
- VirtualWebSocketClient.prototype.resume = function () {
946
- return __awaiter(this, void 0, void 0, function () {
947
- var e_9;
948
- return __generator(this, function (_a) {
949
- switch (_a.label) {
950
- case 0:
951
- this.watchStatus = WATCH_STATUS.RESUMING;
952
- console.log("[realtime] client resuming with " + (this.sessionInfo ? 'REBUILD_WATCH' : 'INIT_WATCH') + " (" + this.collectionName + " " + this.query + ") (" + this.watchId + ")");
953
- _a.label = 1;
954
- case 1:
955
- _a.trys.push([1, 3, , 4]);
956
- return [4, (this.sessionInfo ? this.rebuildWatch() : this.initWatch())];
957
- case 2:
958
- _a.sent();
959
- console.log("[realtime] client successfully resumed (" + this.collectionName + " " + this.query + ") (" + this.watchId + ")");
960
- return [3, 4];
961
- case 3:
962
- e_9 = _a.sent();
963
- console.error("[realtime] client resume failed (" + this.collectionName + " " + this.query + ") (" + this.watchId + ")", e_9);
964
- return [3, 4];
965
- case 4: return [2];
966
- }
967
- });
968
- });
969
- };
970
- return VirtualWebSocketClient;
971
- }());
972
- exports.VirtualWebSocketClient = VirtualWebSocketClient;
973
- function getPublicEvent(event) {
974
- var e = {
975
- id: event.ID,
976
- dataType: event.DataType,
977
- queueType: event.QueueType,
978
- docId: event.DocID,
979
- doc: event.Doc && event.Doc !== '{}' ? JSON.parse(event.Doc) : undefined
980
- };
981
- if (event.DataType === 'update') {
982
- if (event.UpdatedFields) {
983
- e.updatedFields = JSON.parse(event.UpdatedFields);
984
- }
985
- if (event.removedFields || event.RemovedFields) {
986
- e.removedFields = JSON.parse(event.removedFields);
987
- }
988
- }
989
- return e;
990
- }
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lodash_set_1 = require("lodash.set");
4
+ const lodash_unset_1 = require("lodash.unset");
5
+ const lodash_clonedeep_1 = require("lodash.clonedeep");
6
+ const message_1 = require("./message");
7
+ const error_1 = require("../utils/error");
8
+ const error_config_1 = require("../config/error.config");
9
+ const utils_1 = require("../utils/utils");
10
+ const listener_1 = require("./listener");
11
+ const snapshot_1 = require("./snapshot");
12
+ const error_2 = require("./error");
13
+ var WATCH_STATUS;
14
+ (function (WATCH_STATUS) {
15
+ WATCH_STATUS["LOGGINGIN"] = "LOGGINGIN";
16
+ WATCH_STATUS["INITING"] = "INITING";
17
+ WATCH_STATUS["REBUILDING"] = "REBUILDING";
18
+ WATCH_STATUS["ACTIVE"] = "ACTIVE";
19
+ WATCH_STATUS["ERRORED"] = "ERRORED";
20
+ WATCH_STATUS["CLOSING"] = "CLOSING";
21
+ WATCH_STATUS["CLOSED"] = "CLOSED";
22
+ WATCH_STATUS["PAUSED"] = "PAUSED";
23
+ WATCH_STATUS["RESUMING"] = "RESUMING";
24
+ })(WATCH_STATUS || (WATCH_STATUS = {}));
25
+ const DEFAULT_WAIT_TIME_ON_UNKNOWN_ERROR = 100;
26
+ const DEFAULT_MAX_AUTO_RETRY_ON_ERROR = 2;
27
+ const DEFAULT_MAX_SEND_ACK_AUTO_RETRY_ON_ERROR = 2;
28
+ const DEFAULT_SEND_ACK_DEBOUNCE_TIMEOUT = 10 * 1000;
29
+ const DEFAULT_INIT_WATCH_TIMEOUT = 10 * 1000;
30
+ const DEFAULT_REBUILD_WATCH_TIMEOUT = 10 * 1000;
31
+ class VirtualWebSocketClient {
32
+ constructor(options) {
33
+ this.watchStatus = WATCH_STATUS.INITING;
34
+ this._login = async (envId, refresh) => {
35
+ this.watchStatus = WATCH_STATUS.LOGGINGIN;
36
+ const loginResult = await this.login(envId, refresh);
37
+ if (!this.envId) {
38
+ this.envId = loginResult.envId;
39
+ }
40
+ return loginResult;
41
+ };
42
+ this.initWatch = async (forceRefreshLogin) => {
43
+ if (this._initWatchPromise) {
44
+ return this._initWatchPromise;
45
+ }
46
+ this._initWatchPromise = new Promise(async (resolve, reject) => {
47
+ try {
48
+ if (this.watchStatus === WATCH_STATUS.PAUSED) {
49
+ console.log('[realtime] initWatch cancelled on pause');
50
+ return resolve();
51
+ }
52
+ const { envId } = await this._login(this.envId, forceRefreshLogin);
53
+ if (this.watchStatus === WATCH_STATUS.PAUSED) {
54
+ console.log('[realtime] initWatch cancelled on pause');
55
+ return resolve();
56
+ }
57
+ this.watchStatus = WATCH_STATUS.INITING;
58
+ const initWatchMsg = {
59
+ watchId: this.watchId,
60
+ requestId: message_1.genRequestId(),
61
+ msgType: 'INIT_WATCH',
62
+ msgData: {
63
+ envId,
64
+ collName: this.collectionName,
65
+ query: this.query,
66
+ limit: this.limit,
67
+ orderBy: this.orderBy
68
+ }
69
+ };
70
+ const initEventMsg = await this.send({
71
+ msg: initWatchMsg,
72
+ waitResponse: true,
73
+ skipOnMessage: true,
74
+ timeout: DEFAULT_INIT_WATCH_TIMEOUT
75
+ });
76
+ const { events, currEvent } = initEventMsg.msgData;
77
+ this.sessionInfo = {
78
+ queryID: initEventMsg.msgData.queryID,
79
+ currentEventId: currEvent - 1,
80
+ currentDocs: []
81
+ };
82
+ if (events.length > 0) {
83
+ for (const e of events) {
84
+ e.ID = currEvent;
85
+ }
86
+ this.handleServerEvents(initEventMsg);
87
+ }
88
+ else {
89
+ this.sessionInfo.currentEventId = currEvent;
90
+ const snapshot = new snapshot_1.Snapshot({
91
+ id: currEvent,
92
+ docChanges: [],
93
+ docs: [],
94
+ type: 'init'
95
+ });
96
+ this.listener.onChange(snapshot);
97
+ this.scheduleSendACK();
98
+ }
99
+ this.onWatchStart(this, this.sessionInfo.queryID);
100
+ this.watchStatus = WATCH_STATUS.ACTIVE;
101
+ this._availableRetries.INIT_WATCH = DEFAULT_MAX_AUTO_RETRY_ON_ERROR;
102
+ resolve();
103
+ }
104
+ catch (e) {
105
+ this.handleWatchEstablishmentError(e, {
106
+ operationName: 'INIT_WATCH',
107
+ resolve,
108
+ reject
109
+ });
110
+ }
111
+ });
112
+ let success = false;
113
+ try {
114
+ await this._initWatchPromise;
115
+ success = true;
116
+ }
117
+ finally {
118
+ this._initWatchPromise = undefined;
119
+ }
120
+ console.log(`[realtime] initWatch ${success ? 'success' : 'fail'}`);
121
+ };
122
+ this.rebuildWatch = async (forceRefreshLogin) => {
123
+ if (this._rebuildWatchPromise) {
124
+ return this._rebuildWatchPromise;
125
+ }
126
+ this._rebuildWatchPromise = new Promise(async (resolve, reject) => {
127
+ try {
128
+ if (this.watchStatus === WATCH_STATUS.PAUSED) {
129
+ console.log('[realtime] rebuildWatch cancelled on pause');
130
+ return resolve();
131
+ }
132
+ const { envId } = await this._login(this.envId, forceRefreshLogin);
133
+ if (!this.sessionInfo) {
134
+ throw new Error('can not rebuildWatch without a successful initWatch (lack of sessionInfo)');
135
+ }
136
+ if (this.watchStatus === WATCH_STATUS.PAUSED) {
137
+ console.log('[realtime] rebuildWatch cancelled on pause');
138
+ return resolve();
139
+ }
140
+ this.watchStatus = WATCH_STATUS.REBUILDING;
141
+ const rebuildWatchMsg = {
142
+ watchId: this.watchId,
143
+ requestId: message_1.genRequestId(),
144
+ msgType: 'REBUILD_WATCH',
145
+ msgData: {
146
+ envId,
147
+ collName: this.collectionName,
148
+ queryID: this.sessionInfo.queryID,
149
+ eventID: this.sessionInfo.currentEventId
150
+ }
151
+ };
152
+ const nextEventMsg = await this.send({
153
+ msg: rebuildWatchMsg,
154
+ waitResponse: true,
155
+ skipOnMessage: false,
156
+ timeout: DEFAULT_REBUILD_WATCH_TIMEOUT
157
+ });
158
+ this.handleServerEvents(nextEventMsg);
159
+ this.watchStatus = WATCH_STATUS.ACTIVE;
160
+ this._availableRetries.REBUILD_WATCH = DEFAULT_MAX_AUTO_RETRY_ON_ERROR;
161
+ resolve();
162
+ }
163
+ catch (e) {
164
+ this.handleWatchEstablishmentError(e, {
165
+ operationName: 'REBUILD_WATCH',
166
+ resolve,
167
+ reject
168
+ });
169
+ }
170
+ });
171
+ let success = false;
172
+ try {
173
+ await this._rebuildWatchPromise;
174
+ success = true;
175
+ }
176
+ finally {
177
+ this._rebuildWatchPromise = undefined;
178
+ }
179
+ console.log(`[realtime] rebuildWatch ${success ? 'success' : 'fail'}`);
180
+ };
181
+ this.handleWatchEstablishmentError = async (e, options) => {
182
+ const isInitWatch = options.operationName === 'INIT_WATCH';
183
+ const abortWatch = () => {
184
+ this.closeWithError(new error_1.CloudSDKError({
185
+ errCode: isInitWatch
186
+ ? error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_INIT_WATCH_FAIL
187
+ : error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_REBUILD_WATCH_FAIL,
188
+ errMsg: e
189
+ }));
190
+ options.reject(e);
191
+ };
192
+ const retry = (refreshLogin) => {
193
+ if (this.useRetryTicket(options.operationName)) {
194
+ if (isInitWatch) {
195
+ this._initWatchPromise = undefined;
196
+ options.resolve(this.initWatch(refreshLogin));
197
+ }
198
+ else {
199
+ this._rebuildWatchPromise = undefined;
200
+ options.resolve(this.rebuildWatch(refreshLogin));
201
+ }
202
+ }
203
+ else {
204
+ abortWatch();
205
+ }
206
+ };
207
+ this.handleCommonError(e, {
208
+ onSignError: () => retry(true),
209
+ onTimeoutError: () => retry(false),
210
+ onNotRetryableError: abortWatch,
211
+ onCancelledError: options.reject,
212
+ onUnknownError: async () => {
213
+ try {
214
+ const onWSDisconnected = async () => {
215
+ this.pause();
216
+ await this.onceWSConnected();
217
+ retry(true);
218
+ };
219
+ if (!this.isWSConnected()) {
220
+ await onWSDisconnected();
221
+ }
222
+ else {
223
+ await utils_1.sleep(DEFAULT_WAIT_TIME_ON_UNKNOWN_ERROR);
224
+ if (this.watchStatus === WATCH_STATUS.PAUSED) {
225
+ options.reject(new error_1.CancelledError(`${options.operationName} cancelled due to pause after unknownError`));
226
+ }
227
+ else if (!this.isWSConnected()) {
228
+ await onWSDisconnected();
229
+ }
230
+ else {
231
+ retry(false);
232
+ }
233
+ }
234
+ }
235
+ catch (e) {
236
+ retry(true);
237
+ }
238
+ }
239
+ });
240
+ };
241
+ this.closeWatch = async () => {
242
+ const queryId = this.sessionInfo ? this.sessionInfo.queryID : '';
243
+ if (this.watchStatus !== WATCH_STATUS.ACTIVE) {
244
+ this.watchStatus = WATCH_STATUS.CLOSED;
245
+ this.onWatchClose(this, queryId);
246
+ return;
247
+ }
248
+ try {
249
+ this.watchStatus = WATCH_STATUS.CLOSING;
250
+ const closeWatchMsg = {
251
+ watchId: this.watchId,
252
+ requestId: message_1.genRequestId(),
253
+ msgType: 'CLOSE_WATCH',
254
+ msgData: null
255
+ };
256
+ await this.send({
257
+ msg: closeWatchMsg
258
+ });
259
+ this.sessionInfo = undefined;
260
+ this.watchStatus = WATCH_STATUS.CLOSED;
261
+ }
262
+ catch (e) {
263
+ this.closeWithError(new error_1.CloudSDKError({
264
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_CLOSE_WATCH_FAIL,
265
+ errMsg: e
266
+ }));
267
+ }
268
+ finally {
269
+ this.onWatchClose(this, queryId);
270
+ }
271
+ };
272
+ this.scheduleSendACK = () => {
273
+ this.clearACKSchedule();
274
+ this._ackTimeoutId = setTimeout(() => {
275
+ if (this._waitExpectedTimeoutId) {
276
+ this.scheduleSendACK();
277
+ }
278
+ else {
279
+ this.sendACK();
280
+ }
281
+ }, DEFAULT_SEND_ACK_DEBOUNCE_TIMEOUT);
282
+ };
283
+ this.clearACKSchedule = () => {
284
+ if (this._ackTimeoutId) {
285
+ clearTimeout(this._ackTimeoutId);
286
+ }
287
+ };
288
+ this.sendACK = async () => {
289
+ try {
290
+ if (this.watchStatus !== WATCH_STATUS.ACTIVE) {
291
+ this.scheduleSendACK();
292
+ return;
293
+ }
294
+ if (!this.sessionInfo) {
295
+ console.warn('[realtime listener] can not send ack without a successful initWatch (lack of sessionInfo)');
296
+ return;
297
+ }
298
+ const ackMsg = {
299
+ watchId: this.watchId,
300
+ requestId: message_1.genRequestId(),
301
+ msgType: 'CHECK_LAST',
302
+ msgData: {
303
+ queryID: this.sessionInfo.queryID,
304
+ eventID: this.sessionInfo.currentEventId
305
+ }
306
+ };
307
+ await this.send({
308
+ msg: ackMsg
309
+ });
310
+ this.scheduleSendACK();
311
+ }
312
+ catch (e) {
313
+ if (error_2.isRealtimeErrorMessageError(e)) {
314
+ const msg = e.payload;
315
+ switch (msg.msgData.code) {
316
+ case 'CHECK_LOGIN_FAILED':
317
+ case 'SIGN_EXPIRED_ERROR':
318
+ case 'SIGN_INVALID_ERROR':
319
+ case 'SIGN_PARAM_INVALID': {
320
+ this.rebuildWatch();
321
+ return;
322
+ }
323
+ case 'QUERYID_INVALID_ERROR':
324
+ case 'SYS_ERR':
325
+ case 'INVALIID_ENV':
326
+ case 'COLLECTION_PERMISSION_DENIED': {
327
+ this.closeWithError(new error_1.CloudSDKError({
328
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_CHECK_LAST_FAIL,
329
+ errMsg: msg.msgData.code
330
+ }));
331
+ return;
332
+ }
333
+ default: {
334
+ break;
335
+ }
336
+ }
337
+ }
338
+ if (this._availableRetries.CHECK_LAST &&
339
+ this._availableRetries.CHECK_LAST > 0) {
340
+ this._availableRetries.CHECK_LAST--;
341
+ this.scheduleSendACK();
342
+ }
343
+ else {
344
+ this.closeWithError(new error_1.CloudSDKError({
345
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_CHECK_LAST_FAIL,
346
+ errMsg: e
347
+ }));
348
+ }
349
+ }
350
+ };
351
+ this.handleCommonError = (e, options) => {
352
+ if (error_2.isRealtimeErrorMessageError(e)) {
353
+ const msg = e.payload;
354
+ switch (msg.msgData.code) {
355
+ case 'CHECK_LOGIN_FAILED':
356
+ case 'SIGN_EXPIRED_ERROR':
357
+ case 'SIGN_INVALID_ERROR':
358
+ case 'SIGN_PARAM_INVALID': {
359
+ options.onSignError(e);
360
+ return;
361
+ }
362
+ case 'QUERYID_INVALID_ERROR':
363
+ case 'SYS_ERR':
364
+ case 'INVALIID_ENV':
365
+ case 'COLLECTION_PERMISSION_DENIED': {
366
+ options.onNotRetryableError(e);
367
+ return;
368
+ }
369
+ default: {
370
+ options.onNotRetryableError(e);
371
+ return;
372
+ }
373
+ }
374
+ }
375
+ else if (error_1.isTimeoutError(e)) {
376
+ options.onTimeoutError(e);
377
+ return;
378
+ }
379
+ else if (error_1.isCancelledError(e)) {
380
+ options.onCancelledError(e);
381
+ return;
382
+ }
383
+ options.onUnknownError(e);
384
+ };
385
+ this.watchId = `watchid_${+new Date()}_${Math.random()}`;
386
+ this.envId = options.envId;
387
+ this.collectionName = options.collectionName;
388
+ this.query = options.query;
389
+ this.limit = options.limit;
390
+ this.orderBy = options.orderBy;
391
+ this.send = options.send;
392
+ this.login = options.login;
393
+ this.isWSConnected = options.isWSConnected;
394
+ this.onceWSConnected = options.onceWSConnected;
395
+ this.getWaitExpectedTimeoutLength = options.getWaitExpectedTimeoutLength;
396
+ this.onWatchStart = options.onWatchStart;
397
+ this.onWatchClose = options.onWatchClose;
398
+ this.debug = options.debug;
399
+ this._availableRetries = {
400
+ INIT_WATCH: DEFAULT_MAX_AUTO_RETRY_ON_ERROR,
401
+ REBUILD_WATCH: DEFAULT_MAX_AUTO_RETRY_ON_ERROR,
402
+ CHECK_LAST: DEFAULT_MAX_SEND_ACK_AUTO_RETRY_ON_ERROR
403
+ };
404
+ this.listener = new listener_1.RealtimeListener({
405
+ close: this.closeWatch,
406
+ onChange: options.onChange,
407
+ onError: options.onError,
408
+ debug: this.debug,
409
+ virtualClient: this
410
+ });
411
+ this.initWatch();
412
+ }
413
+ useRetryTicket(operationName) {
414
+ if (this._availableRetries[operationName] &&
415
+ this._availableRetries[operationName] > 0) {
416
+ this._availableRetries[operationName]--;
417
+ console.log(`[realtime] ${operationName} use a retry ticket, now only ${this._availableRetries[operationName]} retry left`);
418
+ return true;
419
+ }
420
+ return false;
421
+ }
422
+ async handleServerEvents(msg) {
423
+ try {
424
+ this.scheduleSendACK();
425
+ await this._handleServerEvents(msg);
426
+ this._postHandleServerEventsValidityCheck(msg);
427
+ }
428
+ catch (e) {
429
+ console.error('[realtime listener] internal non-fatal error: handle server events failed with error: ', e);
430
+ throw e;
431
+ }
432
+ }
433
+ async _handleServerEvents(msg) {
434
+ const { requestId } = msg;
435
+ const { events } = msg.msgData;
436
+ const { msgType } = msg;
437
+ if (!events.length || !this.sessionInfo) {
438
+ return;
439
+ }
440
+ const sessionInfo = this.sessionInfo;
441
+ let allChangeEvents;
442
+ try {
443
+ allChangeEvents = events.map(getPublicEvent);
444
+ }
445
+ catch (e) {
446
+ this.closeWithError(new error_1.CloudSDKError({
447
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_RECEIVE_INVALID_SERVER_DATA,
448
+ errMsg: e
449
+ }));
450
+ return;
451
+ }
452
+ let docs = [...sessionInfo.currentDocs];
453
+ let initEncountered = false;
454
+ for (let i = 0, len = allChangeEvents.length; i < len; i++) {
455
+ const change = allChangeEvents[i];
456
+ if (sessionInfo.currentEventId >= change.id) {
457
+ if (!allChangeEvents[i - 1] || change.id > allChangeEvents[i - 1].id) {
458
+ console.warn(`[realtime] duplicate event received, cur ${sessionInfo.currentEventId} but got ${change.id}`);
459
+ }
460
+ else {
461
+ console.error(`[realtime listener] server non-fatal error: events out of order (the latter event's id is smaller than that of the former) (requestId ${requestId})`);
462
+ }
463
+ continue;
464
+ }
465
+ else if (sessionInfo.currentEventId === change.id - 1) {
466
+ switch (change.dataType) {
467
+ case 'update': {
468
+ if (!change.doc) {
469
+ switch (change.queueType) {
470
+ case 'update':
471
+ case 'dequeue': {
472
+ const localDoc = docs.find(doc => doc._id === change.docId);
473
+ if (localDoc) {
474
+ const doc = lodash_clonedeep_1.default(localDoc);
475
+ if (change.updatedFields) {
476
+ for (const fieldPath in change.updatedFields) {
477
+ lodash_set_1.default(doc, fieldPath, change.updatedFields[fieldPath]);
478
+ }
479
+ }
480
+ if (change.removedFields) {
481
+ for (const fieldPath of change.removedFields) {
482
+ lodash_unset_1.default(doc, fieldPath);
483
+ }
484
+ }
485
+ change.doc = doc;
486
+ }
487
+ else {
488
+ console.error('[realtime listener] internal non-fatal server error: unexpected update dataType event where no doc is associated.');
489
+ }
490
+ break;
491
+ }
492
+ case 'enqueue': {
493
+ const err = new error_1.CloudSDKError({
494
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_UNEXPECTED_FATAL_ERROR,
495
+ errMsg: `HandleServerEvents: full doc is not provided with dataType="update" and queueType="enqueue" (requestId ${msg.requestId})`
496
+ });
497
+ this.closeWithError(err);
498
+ throw err;
499
+ }
500
+ default: {
501
+ break;
502
+ }
503
+ }
504
+ }
505
+ break;
506
+ }
507
+ case 'replace': {
508
+ if (!change.doc) {
509
+ const err = new error_1.CloudSDKError({
510
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_UNEXPECTED_FATAL_ERROR,
511
+ errMsg: `HandleServerEvents: full doc is not provided with dataType="replace" (requestId ${msg.requestId})`
512
+ });
513
+ this.closeWithError(err);
514
+ throw err;
515
+ }
516
+ break;
517
+ }
518
+ case 'remove': {
519
+ const doc = docs.find(doc => doc._id === change.docId);
520
+ if (doc) {
521
+ change.doc = doc;
522
+ }
523
+ else {
524
+ console.error('[realtime listener] internal non-fatal server error: unexpected remove event where no doc is associated.');
525
+ }
526
+ break;
527
+ }
528
+ case 'limit': {
529
+ if (!change.doc) {
530
+ switch (change.queueType) {
531
+ case 'dequeue': {
532
+ const doc = docs.find(doc => doc._id === change.docId);
533
+ if (doc) {
534
+ change.doc = doc;
535
+ }
536
+ else {
537
+ console.error('[realtime listener] internal non-fatal server error: unexpected limit dataType event where no doc is associated.');
538
+ }
539
+ break;
540
+ }
541
+ case 'enqueue': {
542
+ const err = new error_1.CloudSDKError({
543
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_UNEXPECTED_FATAL_ERROR,
544
+ errMsg: `HandleServerEvents: full doc is not provided with dataType="limit" and queueType="enqueue" (requestId ${msg.requestId})`
545
+ });
546
+ this.closeWithError(err);
547
+ throw err;
548
+ }
549
+ default: {
550
+ break;
551
+ }
552
+ }
553
+ }
554
+ break;
555
+ }
556
+ }
557
+ switch (change.queueType) {
558
+ case 'init': {
559
+ if (!initEncountered) {
560
+ initEncountered = true;
561
+ docs = [change.doc];
562
+ }
563
+ else {
564
+ docs.push(change.doc);
565
+ }
566
+ break;
567
+ }
568
+ case 'enqueue': {
569
+ docs.push(change.doc);
570
+ break;
571
+ }
572
+ case 'dequeue': {
573
+ const ind = docs.findIndex(doc => doc._id === change.docId);
574
+ if (ind > -1) {
575
+ docs.splice(ind, 1);
576
+ }
577
+ else {
578
+ console.error('[realtime listener] internal non-fatal server error: unexpected dequeue event where no doc is associated.');
579
+ }
580
+ break;
581
+ }
582
+ case 'update': {
583
+ const ind = docs.findIndex(doc => doc._id === change.docId);
584
+ if (ind > -1) {
585
+ docs[ind] = change.doc;
586
+ }
587
+ else {
588
+ console.error('[realtime listener] internal non-fatal server error: unexpected queueType update event where no doc is associated.');
589
+ }
590
+ break;
591
+ }
592
+ }
593
+ if (i === len - 1 ||
594
+ (allChangeEvents[i + 1] && allChangeEvents[i + 1].id !== change.id)) {
595
+ const docsSnapshot = [...docs];
596
+ const docChanges = allChangeEvents
597
+ .slice(0, i + 1)
598
+ .filter(c => c.id === change.id);
599
+ this.sessionInfo.currentEventId = change.id;
600
+ this.sessionInfo.currentDocs = docs;
601
+ const snapshot = new snapshot_1.Snapshot({
602
+ id: change.id,
603
+ docChanges,
604
+ docs: docsSnapshot,
605
+ msgType
606
+ });
607
+ this.listener.onChange(snapshot);
608
+ }
609
+ }
610
+ else {
611
+ console.warn(`[realtime listener] event received is out of order, cur ${this.sessionInfo.currentEventId} but got ${change.id}`);
612
+ await this.rebuildWatch();
613
+ return;
614
+ }
615
+ }
616
+ }
617
+ _postHandleServerEventsValidityCheck(msg) {
618
+ if (!this.sessionInfo) {
619
+ console.error('[realtime listener] internal non-fatal error: sessionInfo lost after server event handling, this should never occur');
620
+ return;
621
+ }
622
+ if (this.sessionInfo.expectEventId &&
623
+ this.sessionInfo.currentEventId >= this.sessionInfo.expectEventId) {
624
+ this.clearWaitExpectedEvent();
625
+ }
626
+ if (this.sessionInfo.currentEventId < msg.msgData.currEvent) {
627
+ console.warn('[realtime listener] internal non-fatal error: client eventId does not match with server event id after server event handling');
628
+ return;
629
+ }
630
+ }
631
+ clearWaitExpectedEvent() {
632
+ if (this._waitExpectedTimeoutId) {
633
+ clearTimeout(this._waitExpectedTimeoutId);
634
+ this._waitExpectedTimeoutId = undefined;
635
+ }
636
+ }
637
+ onMessage(msg) {
638
+ switch (this.watchStatus) {
639
+ case WATCH_STATUS.PAUSED: {
640
+ if (msg.msgType !== 'ERROR') {
641
+ return;
642
+ }
643
+ break;
644
+ }
645
+ case WATCH_STATUS.LOGGINGIN:
646
+ case WATCH_STATUS.INITING:
647
+ case WATCH_STATUS.REBUILDING: {
648
+ console.warn(`[realtime listener] internal non-fatal error: unexpected message received while ${this.watchStatus}`);
649
+ return;
650
+ }
651
+ case WATCH_STATUS.CLOSED: {
652
+ console.warn('[realtime listener] internal non-fatal error: unexpected message received when the watch has closed');
653
+ return;
654
+ }
655
+ case WATCH_STATUS.ERRORED: {
656
+ console.warn('[realtime listener] internal non-fatal error: unexpected message received when the watch has ended with error');
657
+ return;
658
+ }
659
+ }
660
+ if (!this.sessionInfo) {
661
+ console.warn('[realtime listener] internal non-fatal error: sessionInfo not found while message is received.');
662
+ return;
663
+ }
664
+ this.scheduleSendACK();
665
+ switch (msg.msgType) {
666
+ case 'NEXT_EVENT': {
667
+ console.warn(`nextevent ${msg.msgData.currEvent} ignored`, msg);
668
+ this.handleServerEvents(msg);
669
+ break;
670
+ }
671
+ case 'CHECK_EVENT': {
672
+ if (this.sessionInfo.currentEventId < msg.msgData.currEvent) {
673
+ this.sessionInfo.expectEventId = msg.msgData.currEvent;
674
+ this.clearWaitExpectedEvent();
675
+ this._waitExpectedTimeoutId = setTimeout(() => {
676
+ this.rebuildWatch();
677
+ }, this.getWaitExpectedTimeoutLength());
678
+ console.log(`[realtime] waitExpectedTimeoutLength ${this.getWaitExpectedTimeoutLength()}`);
679
+ }
680
+ break;
681
+ }
682
+ case 'ERROR': {
683
+ this.closeWithError(new error_1.CloudSDKError({
684
+ errCode: error_config_1.ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_SERVER_ERROR_MSG,
685
+ errMsg: `${msg.msgData.code} - ${msg.msgData.message}`
686
+ }));
687
+ break;
688
+ }
689
+ default: {
690
+ console.warn(`[realtime listener] virtual client receive unexpected msg ${msg.msgType}: `, msg);
691
+ break;
692
+ }
693
+ }
694
+ }
695
+ closeWithError(error) {
696
+ this.watchStatus = WATCH_STATUS.ERRORED;
697
+ this.clearACKSchedule();
698
+ this.listener.onError(error);
699
+ this.onWatchClose(this, (this.sessionInfo && this.sessionInfo.queryID) || '');
700
+ console.log(`[realtime] client closed (${this.collectionName} ${this.query}) (watchId ${this.watchId})`);
701
+ }
702
+ pause() {
703
+ this.watchStatus = WATCH_STATUS.PAUSED;
704
+ console.log(`[realtime] client paused (${this.collectionName} ${this.query}) (watchId ${this.watchId})`);
705
+ }
706
+ async resume() {
707
+ this.watchStatus = WATCH_STATUS.RESUMING;
708
+ console.log(`[realtime] client resuming with ${this.sessionInfo ? 'REBUILD_WATCH' : 'INIT_WATCH'} (${this.collectionName} ${this.query}) (${this.watchId})`);
709
+ try {
710
+ await (this.sessionInfo ? this.rebuildWatch() : this.initWatch());
711
+ console.log(`[realtime] client successfully resumed (${this.collectionName} ${this.query}) (${this.watchId})`);
712
+ }
713
+ catch (e) {
714
+ console.error(`[realtime] client resume failed (${this.collectionName} ${this.query}) (${this.watchId})`, e);
715
+ }
716
+ }
717
+ }
718
+ exports.VirtualWebSocketClient = VirtualWebSocketClient;
719
+ function getPublicEvent(event) {
720
+ const e = {
721
+ id: event.ID,
722
+ dataType: event.DataType,
723
+ queueType: event.QueueType,
724
+ docId: event.DocID,
725
+ doc: event.Doc && event.Doc !== '{}' ? JSON.parse(event.Doc) : undefined
726
+ };
727
+ if (event.DataType === 'update') {
728
+ if (event.UpdatedFields) {
729
+ e.updatedFields = JSON.parse(event.UpdatedFields);
730
+ }
731
+ if (event.removedFields || event.RemovedFields) {
732
+ e.removedFields = JSON.parse(event.removedFields);
733
+ }
734
+ }
735
+ return e;
736
+ }