mongodb-livedata-server 0.1.3 → 0.1.5

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 (92) hide show
  1. package/README.md +2 -2
  2. package/dist/livedata_server.d.ts +4 -4
  3. package/dist/livedata_server.js +11 -11
  4. package/dist/meteor/binary-heap/max_heap.d.ts +31 -31
  5. package/dist/meteor/binary-heap/max_heap.js +186 -186
  6. package/dist/meteor/binary-heap/min_heap.d.ts +6 -6
  7. package/dist/meteor/binary-heap/min_heap.js +17 -17
  8. package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -11
  9. package/dist/meteor/binary-heap/min_max_heap.js +48 -48
  10. package/dist/meteor/callback-hook/hook.d.ts +11 -11
  11. package/dist/meteor/callback-hook/hook.js +78 -78
  12. package/dist/meteor/ddp/crossbar.d.ts +15 -15
  13. package/dist/meteor/ddp/crossbar.js +136 -136
  14. package/dist/meteor/ddp/heartbeat.d.ts +19 -19
  15. package/dist/meteor/ddp/heartbeat.js +77 -77
  16. package/dist/meteor/ddp/livedata_server.d.ts +141 -142
  17. package/dist/meteor/ddp/livedata_server.js +403 -403
  18. package/dist/meteor/ddp/method-invocation.d.ts +35 -35
  19. package/dist/meteor/ddp/method-invocation.js +72 -72
  20. package/dist/meteor/ddp/random-stream.d.ts +8 -8
  21. package/dist/meteor/ddp/random-stream.js +100 -100
  22. package/dist/meteor/ddp/session-collection-view.d.ts +20 -20
  23. package/dist/meteor/ddp/session-collection-view.js +106 -106
  24. package/dist/meteor/ddp/session-document-view.d.ts +8 -8
  25. package/dist/meteor/ddp/session-document-view.js +82 -82
  26. package/dist/meteor/ddp/session.d.ts +75 -75
  27. package/dist/meteor/ddp/session.js +590 -590
  28. package/dist/meteor/ddp/stream_server.d.ts +20 -21
  29. package/dist/meteor/ddp/stream_server.js +181 -181
  30. package/dist/meteor/ddp/subscription.d.ts +94 -94
  31. package/dist/meteor/ddp/subscription.js +370 -370
  32. package/dist/meteor/ddp/utils.d.ts +8 -8
  33. package/dist/meteor/ddp/utils.js +104 -104
  34. package/dist/meteor/ddp/writefence.d.ts +20 -20
  35. package/dist/meteor/ddp/writefence.js +111 -111
  36. package/dist/meteor/diff-sequence/diff.d.ts +17 -17
  37. package/dist/meteor/diff-sequence/diff.js +257 -257
  38. package/dist/meteor/ejson/ejson.d.ts +82 -82
  39. package/dist/meteor/ejson/ejson.js +568 -569
  40. package/dist/meteor/ejson/stringify.d.ts +2 -2
  41. package/dist/meteor/ejson/stringify.js +119 -119
  42. package/dist/meteor/ejson/utils.d.ts +12 -12
  43. package/dist/meteor/ejson/utils.js +42 -42
  44. package/dist/meteor/mongo/caching_change_observer.d.ts +16 -16
  45. package/dist/meteor/mongo/caching_change_observer.js +63 -63
  46. package/dist/meteor/mongo/doc_fetcher.d.ts +7 -7
  47. package/dist/meteor/mongo/doc_fetcher.js +53 -53
  48. package/dist/meteor/mongo/geojson_utils.d.ts +3 -3
  49. package/dist/meteor/mongo/geojson_utils.js +40 -41
  50. package/dist/meteor/mongo/live_connection.d.ts +28 -28
  51. package/dist/meteor/mongo/live_connection.js +264 -264
  52. package/dist/meteor/mongo/live_cursor.d.ts +25 -25
  53. package/dist/meteor/mongo/live_cursor.js +60 -60
  54. package/dist/meteor/mongo/minimongo_common.d.ts +84 -84
  55. package/dist/meteor/mongo/minimongo_common.js +1998 -1998
  56. package/dist/meteor/mongo/minimongo_matcher.d.ts +23 -23
  57. package/dist/meteor/mongo/minimongo_matcher.js +283 -283
  58. package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -16
  59. package/dist/meteor/mongo/minimongo_sorter.js +268 -268
  60. package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -9
  61. package/dist/meteor/mongo/observe_driver_utils.js +72 -73
  62. package/dist/meteor/mongo/observe_multiplexer.d.ts +46 -46
  63. package/dist/meteor/mongo/observe_multiplexer.js +203 -203
  64. package/dist/meteor/mongo/oplog-observe-driver.d.ts +68 -68
  65. package/dist/meteor/mongo/oplog-observe-driver.js +918 -918
  66. package/dist/meteor/mongo/oplog_tailing.d.ts +35 -35
  67. package/dist/meteor/mongo/oplog_tailing.js +352 -352
  68. package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -1
  69. package/dist/meteor/mongo/oplog_v2_converter.js +125 -126
  70. package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -30
  71. package/dist/meteor/mongo/polling_observe_driver.js +216 -221
  72. package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -17
  73. package/dist/meteor/mongo/synchronous-cursor.js +261 -261
  74. package/dist/meteor/mongo/synchronous-queue.d.ts +13 -13
  75. package/dist/meteor/mongo/synchronous-queue.js +110 -110
  76. package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -31
  77. package/dist/meteor/ordered-dict/ordered_dict.js +198 -198
  78. package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -42
  79. package/dist/meteor/random/AbstractRandomGenerator.js +92 -92
  80. package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -13
  81. package/dist/meteor/random/AleaRandomGenerator.js +90 -90
  82. package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -16
  83. package/dist/meteor/random/NodeRandomGenerator.js +42 -42
  84. package/dist/meteor/random/createAleaGenerator.d.ts +2 -2
  85. package/dist/meteor/random/createAleaGenerator.js +32 -32
  86. package/dist/meteor/random/createRandom.d.ts +1 -1
  87. package/dist/meteor/random/createRandom.js +22 -22
  88. package/dist/meteor/random/main.d.ts +1 -1
  89. package/dist/meteor/random/main.js +12 -12
  90. package/dist/meteor/types.d.ts +1 -1
  91. package/dist/meteor/types.js +2 -2
  92. package/package.json +5 -5
@@ -1,370 +1,370 @@
1
- "use strict";
2
- // Ctor for a sub handle: the input to each publish function
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.Subscription = void 0;
5
- const ejson_1 = require("../ejson/ejson");
6
- const main_1 = require("../random/main");
7
- const livedata_server_1 = require("./livedata_server");
8
- // Instance name is this because it's usually referred to as this inside a
9
- // publish
10
- /**
11
- * @summary The server's side of a subscription
12
- * @class Subscription
13
- * @instanceName this
14
- * @showInstanceName true
15
- */
16
- class Subscription {
17
- constructor(_session, _handler, _subscriptionId, _params = [], _name) {
18
- this._session = _session;
19
- this._handler = _handler;
20
- this._subscriptionId = _subscriptionId;
21
- this._params = _params;
22
- this._name = _name;
23
- // Has _deactivate been called?
24
- this._deactivated = false;
25
- // Stop callbacks to g/c this sub. called w/ zero arguments.
26
- this._stopCallbacks = [];
27
- // The set of (collection, documentid) that this subscription has
28
- // an opinion about.
29
- this._documents = new Map();
30
- // Remember if we are ready.
31
- this._ready = false;
32
- // For now, the id filter is going to default to
33
- // the to/from DDP methods on MongoID, to
34
- // specifically deal with mongo/minimongo ObjectIds.
35
- // Later, you will be able to make this be "raw"
36
- // if you want to publish a collection that you know
37
- // just has strings for keys and no funny business, to
38
- // a DDP consumer that isn't minimongo.
39
- this._idFilter = {
40
- idStringify: id => id /*MongoID.idStringify*/,
41
- idParse: id => id /*MongoID.idParse*/
42
- };
43
- /**
44
- * @summary Access inside the publish function. The incoming [connection](#meteor_onconnection) for this subscription.
45
- * @locus Server
46
- * @name connection
47
- * @memberOf Subscription
48
- * @instance
49
- */
50
- this.connection = _session.connectionHandle; // public API object
51
- // Only named subscriptions have IDs, but we need some sort of string
52
- // internally to keep track of all subscriptions inside
53
- // SessionDocumentViews. We use this subscriptionHandle for that.
54
- if (this._subscriptionId) {
55
- this._subscriptionHandle = `N${this._subscriptionId}`;
56
- }
57
- else {
58
- this._subscriptionHandle = `U${main_1.Random.id()}`;
59
- }
60
- // Part of the public API: the user of this sub.
61
- /**
62
- * @summary Access inside the publish function. The id of the logged-in user, or `null` if no user is logged in.
63
- * @locus Server
64
- * @memberOf Subscription
65
- * @name userId
66
- * @instance
67
- */
68
- this.userId = this._session.userId;
69
- }
70
- ;
71
- async _runHandler() {
72
- // XXX should we unblock() here? Either before running the publish
73
- // function, or before running _publishCursor.
74
- //
75
- // Right now, each publish function blocks all future publishes and
76
- // methods waiting on data from Mongo (or whatever else the function
77
- // blocks on). This probably slows page load in common cases.
78
- let resultOrThenable = null;
79
- const oldInvocation = livedata_server_1.DDP._CurrentPublicationInvocation;
80
- try {
81
- livedata_server_1.DDP._CurrentPublicationInvocation = this;
82
- resultOrThenable = (0, livedata_server_1.maybeAuditArgumentChecks)(this._handler, this, (0, ejson_1.clone)(this._params),
83
- // It's OK that this would look weird for universal subscriptions,
84
- // because they have no arguments so there can never be an
85
- // audit-argument-checks failure.
86
- "publisher '" + this._name + "'");
87
- }
88
- catch (e) {
89
- this.error(e);
90
- return;
91
- }
92
- finally {
93
- livedata_server_1.DDP._CurrentPublicationInvocation = oldInvocation;
94
- }
95
- // Did the handler call this.error or this.stop?
96
- if (this._isDeactivated())
97
- return;
98
- // Both conventional and async publish handler functions are supported.
99
- // If an object is returned with a then() function, it is either a promise
100
- // or thenable and will be resolved asynchronously.
101
- const isThenable = resultOrThenable && typeof resultOrThenable.then === 'function';
102
- if (isThenable) {
103
- let result;
104
- try {
105
- result = await resultOrThenable;
106
- }
107
- catch (e) {
108
- this.error(e);
109
- }
110
- await this._publishHandlerResult(result);
111
- }
112
- else {
113
- await this._publishHandlerResult(resultOrThenable);
114
- }
115
- }
116
- async _publishHandlerResult(res) {
117
- // SPECIAL CASE: Instead of writing their own callbacks that invoke
118
- // this.added/changed/ready/etc, the user can just return a collection
119
- // cursor or array of cursors from the publish function; we call their
120
- // _publishCursor method which starts observing the cursor and publishes the
121
- // results. Note that _publishCursor does NOT call ready().
122
- //
123
- // XXX This uses an undocumented interface which only the Mongo cursor
124
- // interface publishes. Should we make this interface public and encourage
125
- // users to implement it themselves? Arguably, it's unnecessary; users can
126
- // already write their own functions like
127
- // var publishMyReactiveThingy = function (name, handler) {
128
- // Meteor.publish(name, function () {
129
- // var reactiveThingy = handler();
130
- // reactiveThingy.publishMe();
131
- // });
132
- // };
133
- var self = this;
134
- var isCursor = function (c) {
135
- return c && c._publishCursor;
136
- };
137
- if (isCursor(res)) {
138
- try {
139
- await res._publishCursor(self);
140
- }
141
- catch (e) {
142
- self.error(e);
143
- return;
144
- }
145
- // _publishCursor only returns after the initial added callbacks have run.
146
- // mark subscription as ready.
147
- self.ready();
148
- }
149
- else if (Array.isArray(res)) {
150
- // Check all the elements are cursors
151
- if (!res.every(isCursor)) {
152
- self.error(new Error("Publish function returned an array of non-Cursors"));
153
- return;
154
- }
155
- // Find duplicate collection names
156
- // XXX we should support overlapping cursors, but that would require the
157
- // merge box to allow overlap within a subscription
158
- var collectionNames = {};
159
- for (var i = 0; i < res.length; ++i) {
160
- var collectionName = res[i].cursorDescription.collectionName;
161
- if (collectionNames.hasOwnProperty(collectionName)) {
162
- self.error(new Error("Publish function returned multiple cursors for collection " +
163
- collectionName));
164
- return;
165
- }
166
- collectionNames[collectionName] = true;
167
- }
168
- ;
169
- try {
170
- for (const cur of res) {
171
- await cur._publishCursor(self);
172
- }
173
- }
174
- catch (e) {
175
- self.error(e);
176
- return;
177
- }
178
- self.ready();
179
- }
180
- else if (res) {
181
- // Truthy values other than cursors or arrays are probably a
182
- // user mistake (possible returning a Mongo document via, say,
183
- // `coll.findOne()`).
184
- self.error(new Error("Publish function can only return a Cursor or "
185
- + "an array of Cursors"));
186
- }
187
- }
188
- // This calls all stop callbacks and prevents the handler from updating any
189
- // SessionCollectionViews further. It's used when the user unsubscribes or
190
- // disconnects, as well as during setUserId re-runs. It does *NOT* send
191
- // removed messages for the published objects; if that is necessary, call
192
- // _removeAllDocuments first.
193
- _deactivate() {
194
- var self = this;
195
- if (self._deactivated)
196
- return;
197
- self._deactivated = true;
198
- self._callStopCallbacks();
199
- /*Package['facts-base'] && Package['facts-base'].Facts.incrementServerFact(
200
- "livedata", "subscriptions", -1);*/
201
- }
202
- _callStopCallbacks() {
203
- var self = this;
204
- // Tell listeners, so they can clean up
205
- var callbacks = self._stopCallbacks;
206
- self._stopCallbacks = [];
207
- for (const callback of callbacks) {
208
- callback();
209
- }
210
- }
211
- // Send remove messages for every document.
212
- _removeAllDocuments() {
213
- var self = this;
214
- self._documents.forEach(function (collectionDocs, collectionName) {
215
- collectionDocs.forEach(function (strId) {
216
- self.removed(collectionName, self._idFilter.idParse(strId));
217
- });
218
- });
219
- }
220
- // Returns a new Subscription for the same session with the same
221
- // initial creation parameters. This isn't a clone: it doesn't have
222
- // the same _documents cache, stopped state or callbacks; may have a
223
- // different _subscriptionHandle, and gets its userId from the
224
- // session, not from this object.
225
- _recreate() {
226
- var self = this;
227
- return new Subscription(self._session, self._handler, self._subscriptionId, self._params, self._name);
228
- }
229
- /**
230
- * @summary Call inside the publish function. Stops this client's subscription, triggering a call on the client to the `onStop` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. If `error` is not a [`Meteor.Error`](#meteor_error), it will be [sanitized](#meteor_error).
231
- * @locus Server
232
- * @param {Error} error The error to pass to the client.
233
- * @instance
234
- * @memberOf Subscription
235
- */
236
- error(error) {
237
- var self = this;
238
- if (self._isDeactivated())
239
- return;
240
- self._session._stopSubscription(self._subscriptionId, error);
241
- }
242
- // Note that while our DDP client will notice that you've called stop() on the
243
- // server (and clean up its _subscriptions table) we don't actually provide a
244
- // mechanism for an app to notice this (the subscribe onError callback only
245
- // triggers if there is an error).
246
- /**
247
- * @summary Call inside the publish function. Stops this client's subscription and invokes the client's `onStop` callback with no error.
248
- * @locus Server
249
- * @instance
250
- * @memberOf Subscription
251
- */
252
- stop() {
253
- var self = this;
254
- if (self._isDeactivated())
255
- return;
256
- self._session._stopSubscription(self._subscriptionId);
257
- }
258
- /**
259
- * @summary Call inside the publish function. Registers a callback function to run when the subscription is stopped.
260
- * @locus Server
261
- * @memberOf Subscription
262
- * @instance
263
- * @param {Function} func The callback function
264
- */
265
- onStop(func) {
266
- var self = this;
267
- if (self._isDeactivated())
268
- func();
269
- else
270
- self._stopCallbacks.push(func);
271
- }
272
- // This returns true if the sub has been deactivated, *OR* if the session was
273
- // destroyed but the deferred call to _deactivateAllSubscriptions hasn't
274
- // happened yet.
275
- _isDeactivated() {
276
- var self = this;
277
- return self._deactivated || self._session.inQueue === null;
278
- }
279
- initialAdds(collectionName, documents) {
280
- if (this._isDeactivated())
281
- return;
282
- if (this._session.server.getPublicationStrategy(collectionName).doAccountingForCollection) {
283
- let ids = this._documents.get(collectionName);
284
- if (ids == null) {
285
- ids = new Set();
286
- this._documents.set(collectionName, ids);
287
- }
288
- documents.forEach((_doc, id) => ids.add(id));
289
- }
290
- if (this._session.version === "1a")
291
- this._session.initialAdds(this._subscriptionHandle, collectionName, documents);
292
- else
293
- documents.forEach((doc, id) => this._session.added(this._subscriptionHandle, collectionName, id, doc));
294
- }
295
- /**
296
- * @summary Call inside the publish function. Informs the subscriber that a document has been added to the record set.
297
- * @locus Server
298
- * @memberOf Subscription
299
- * @instance
300
- * @param {String} collection The name of the collection that contains the new document.
301
- * @param {String} id The new document's ID.
302
- * @param {Object} fields The fields in the new document. If `_id` is present it is ignored.
303
- */
304
- added(collectionName, id, fields) {
305
- if (this._isDeactivated())
306
- return;
307
- id = this._idFilter.idStringify(id);
308
- if (this._session.server.getPublicationStrategy(collectionName).doAccountingForCollection) {
309
- let ids = this._documents.get(collectionName);
310
- if (ids == null) {
311
- ids = new Set();
312
- this._documents.set(collectionName, ids);
313
- }
314
- ids.add(id);
315
- }
316
- this._session.added(this._subscriptionHandle, collectionName, id, fields);
317
- }
318
- /**
319
- * @summary Call inside the publish function. Informs the subscriber that a document in the record set has been modified.
320
- * @locus Server
321
- * @memberOf Subscription
322
- * @instance
323
- * @param {String} collection The name of the collection that contains the changed document.
324
- * @param {String} id The changed document's ID.
325
- * @param {Object} fields The fields in the document that have changed, together with their new values. If a field is not present in `fields` it was left unchanged; if it is present in `fields` and has a value of `undefined` it was removed from the document. If `_id` is present it is ignored.
326
- */
327
- changed(collectionName, id, fields) {
328
- if (this._isDeactivated())
329
- return;
330
- id = this._idFilter.idStringify(id);
331
- this._session.changed(this._subscriptionHandle, collectionName, id, fields);
332
- }
333
- /**
334
- * @summary Call inside the publish function. Informs the subscriber that a document has been removed from the record set.
335
- * @locus Server
336
- * @memberOf Subscription
337
- * @instance
338
- * @param {String} collection The name of the collection that the document has been removed from.
339
- * @param {String} id The ID of the document that has been removed.
340
- */
341
- removed(collectionName, id) {
342
- if (this._isDeactivated())
343
- return;
344
- id = this._idFilter.idStringify(id);
345
- if (this._session.server.getPublicationStrategy(collectionName).doAccountingForCollection) {
346
- // We don't bother to delete sets of things in a collection if the
347
- // collection is empty. It could break _removeAllDocuments.
348
- this._documents.get(collectionName).delete(id);
349
- }
350
- this._session.removed(this._subscriptionHandle, collectionName, id);
351
- }
352
- /**
353
- * @summary Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the `onReady` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any.
354
- * @locus Server
355
- * @memberOf Subscription
356
- * @instance
357
- */
358
- ready() {
359
- var self = this;
360
- if (self._isDeactivated())
361
- return;
362
- if (!self._subscriptionId)
363
- return; // Unnecessary but ignored for universal sub
364
- if (!self._ready) {
365
- self._session.sendReady([self._subscriptionId]);
366
- self._ready = true;
367
- }
368
- }
369
- }
370
- exports.Subscription = Subscription;
1
+ "use strict";
2
+ // Ctor for a sub handle: the input to each publish function
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Subscription = void 0;
5
+ const ejson_1 = require("../ejson/ejson");
6
+ const main_1 = require("../random/main");
7
+ const livedata_server_1 = require("./livedata_server");
8
+ // Instance name is this because it's usually referred to as this inside a
9
+ // publish
10
+ /**
11
+ * @summary The server's side of a subscription
12
+ * @class Subscription
13
+ * @instanceName this
14
+ * @showInstanceName true
15
+ */
16
+ class Subscription {
17
+ constructor(_session, _handler, _subscriptionId, _params = [], _name) {
18
+ this._session = _session;
19
+ this._handler = _handler;
20
+ this._subscriptionId = _subscriptionId;
21
+ this._params = _params;
22
+ this._name = _name;
23
+ // Has _deactivate been called?
24
+ this._deactivated = false;
25
+ // Stop callbacks to g/c this sub. called w/ zero arguments.
26
+ this._stopCallbacks = [];
27
+ // The set of (collection, documentid) that this subscription has
28
+ // an opinion about.
29
+ this._documents = new Map();
30
+ // Remember if we are ready.
31
+ this._ready = false;
32
+ // For now, the id filter is going to default to
33
+ // the to/from DDP methods on MongoID, to
34
+ // specifically deal with mongo/minimongo ObjectIds.
35
+ // Later, you will be able to make this be "raw"
36
+ // if you want to publish a collection that you know
37
+ // just has strings for keys and no funny business, to
38
+ // a DDP consumer that isn't minimongo.
39
+ this._idFilter = {
40
+ idStringify: id => id /*MongoID.idStringify*/,
41
+ idParse: id => id /*MongoID.idParse*/
42
+ };
43
+ /**
44
+ * @summary Access inside the publish function. The incoming [connection](#meteor_onconnection) for this subscription.
45
+ * @locus Server
46
+ * @name connection
47
+ * @memberOf Subscription
48
+ * @instance
49
+ */
50
+ this.connection = _session.connectionHandle; // public API object
51
+ // Only named subscriptions have IDs, but we need some sort of string
52
+ // internally to keep track of all subscriptions inside
53
+ // SessionDocumentViews. We use this subscriptionHandle for that.
54
+ if (this._subscriptionId) {
55
+ this._subscriptionHandle = `N${this._subscriptionId}`;
56
+ }
57
+ else {
58
+ this._subscriptionHandle = `U${main_1.Random.id()}`;
59
+ }
60
+ // Part of the public API: the user of this sub.
61
+ /**
62
+ * @summary Access inside the publish function. The id of the logged-in user, or `null` if no user is logged in.
63
+ * @locus Server
64
+ * @memberOf Subscription
65
+ * @name userId
66
+ * @instance
67
+ */
68
+ this.userId = this._session.userId;
69
+ }
70
+ ;
71
+ async _runHandler() {
72
+ // XXX should we unblock() here? Either before running the publish
73
+ // function, or before running _publishCursor.
74
+ //
75
+ // Right now, each publish function blocks all future publishes and
76
+ // methods waiting on data from Mongo (or whatever else the function
77
+ // blocks on). This probably slows page load in common cases.
78
+ let resultOrThenable = null;
79
+ const oldInvocation = livedata_server_1.DDP._CurrentPublicationInvocation;
80
+ try {
81
+ livedata_server_1.DDP._CurrentPublicationInvocation = this;
82
+ resultOrThenable = (0, livedata_server_1.maybeAuditArgumentChecks)(this._handler, this, (0, ejson_1.clone)(this._params),
83
+ // It's OK that this would look weird for universal subscriptions,
84
+ // because they have no arguments so there can never be an
85
+ // audit-argument-checks failure.
86
+ "publisher '" + this._name + "'");
87
+ }
88
+ catch (e) {
89
+ this.error(e);
90
+ return;
91
+ }
92
+ finally {
93
+ livedata_server_1.DDP._CurrentPublicationInvocation = oldInvocation;
94
+ }
95
+ // Did the handler call this.error or this.stop?
96
+ if (this._isDeactivated())
97
+ return;
98
+ // Both conventional and async publish handler functions are supported.
99
+ // If an object is returned with a then() function, it is either a promise
100
+ // or thenable and will be resolved asynchronously.
101
+ const isThenable = resultOrThenable && typeof resultOrThenable.then === 'function';
102
+ if (isThenable) {
103
+ let result;
104
+ try {
105
+ result = await resultOrThenable;
106
+ }
107
+ catch (e) {
108
+ this.error(e);
109
+ }
110
+ await this._publishHandlerResult(result);
111
+ }
112
+ else {
113
+ await this._publishHandlerResult(resultOrThenable);
114
+ }
115
+ }
116
+ async _publishHandlerResult(res) {
117
+ // SPECIAL CASE: Instead of writing their own callbacks that invoke
118
+ // this.added/changed/ready/etc, the user can just return a collection
119
+ // cursor or array of cursors from the publish function; we call their
120
+ // _publishCursor method which starts observing the cursor and publishes the
121
+ // results. Note that _publishCursor does NOT call ready().
122
+ //
123
+ // XXX This uses an undocumented interface which only the Mongo cursor
124
+ // interface publishes. Should we make this interface public and encourage
125
+ // users to implement it themselves? Arguably, it's unnecessary; users can
126
+ // already write their own functions like
127
+ // var publishMyReactiveThingy = function (name, handler) {
128
+ // Meteor.publish(name, function () {
129
+ // var reactiveThingy = handler();
130
+ // reactiveThingy.publishMe();
131
+ // });
132
+ // };
133
+ var self = this;
134
+ var isCursor = function (c) {
135
+ return c && c._publishCursor;
136
+ };
137
+ if (isCursor(res)) {
138
+ try {
139
+ await res._publishCursor(self);
140
+ }
141
+ catch (e) {
142
+ self.error(e);
143
+ return;
144
+ }
145
+ // _publishCursor only returns after the initial added callbacks have run.
146
+ // mark subscription as ready.
147
+ self.ready();
148
+ }
149
+ else if (Array.isArray(res)) {
150
+ // Check all the elements are cursors
151
+ if (!res.every(isCursor)) {
152
+ self.error(new Error("Publish function returned an array of non-Cursors"));
153
+ return;
154
+ }
155
+ // Find duplicate collection names
156
+ // XXX we should support overlapping cursors, but that would require the
157
+ // merge box to allow overlap within a subscription
158
+ var collectionNames = {};
159
+ for (var i = 0; i < res.length; ++i) {
160
+ var collectionName = res[i].cursorDescription.collectionName;
161
+ if (collectionNames.hasOwnProperty(collectionName)) {
162
+ self.error(new Error("Publish function returned multiple cursors for collection " +
163
+ collectionName));
164
+ return;
165
+ }
166
+ collectionNames[collectionName] = true;
167
+ }
168
+ ;
169
+ try {
170
+ for (const cur of res) {
171
+ await cur._publishCursor(self);
172
+ }
173
+ }
174
+ catch (e) {
175
+ self.error(e);
176
+ return;
177
+ }
178
+ self.ready();
179
+ }
180
+ else if (res) {
181
+ // Truthy values other than cursors or arrays are probably a
182
+ // user mistake (possible returning a Mongo document via, say,
183
+ // `coll.findOne()`).
184
+ self.error(new Error("Publish function can only return a Cursor or "
185
+ + "an array of Cursors"));
186
+ }
187
+ }
188
+ // This calls all stop callbacks and prevents the handler from updating any
189
+ // SessionCollectionViews further. It's used when the user unsubscribes or
190
+ // disconnects, as well as during setUserId re-runs. It does *NOT* send
191
+ // removed messages for the published objects; if that is necessary, call
192
+ // _removeAllDocuments first.
193
+ _deactivate() {
194
+ var self = this;
195
+ if (self._deactivated)
196
+ return;
197
+ self._deactivated = true;
198
+ self._callStopCallbacks();
199
+ /*Package['facts-base'] && Package['facts-base'].Facts.incrementServerFact(
200
+ "livedata", "subscriptions", -1);*/
201
+ }
202
+ _callStopCallbacks() {
203
+ var self = this;
204
+ // Tell listeners, so they can clean up
205
+ var callbacks = self._stopCallbacks;
206
+ self._stopCallbacks = [];
207
+ for (const callback of callbacks) {
208
+ callback();
209
+ }
210
+ }
211
+ // Send remove messages for every document.
212
+ _removeAllDocuments() {
213
+ var self = this;
214
+ self._documents.forEach(function (collectionDocs, collectionName) {
215
+ collectionDocs.forEach(function (strId) {
216
+ self.removed(collectionName, self._idFilter.idParse(strId));
217
+ });
218
+ });
219
+ }
220
+ // Returns a new Subscription for the same session with the same
221
+ // initial creation parameters. This isn't a clone: it doesn't have
222
+ // the same _documents cache, stopped state or callbacks; may have a
223
+ // different _subscriptionHandle, and gets its userId from the
224
+ // session, not from this object.
225
+ _recreate() {
226
+ var self = this;
227
+ return new Subscription(self._session, self._handler, self._subscriptionId, self._params, self._name);
228
+ }
229
+ /**
230
+ * @summary Call inside the publish function. Stops this client's subscription, triggering a call on the client to the `onStop` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. If `error` is not a [`Meteor.Error`](#meteor_error), it will be [sanitized](#meteor_error).
231
+ * @locus Server
232
+ * @param {Error} error The error to pass to the client.
233
+ * @instance
234
+ * @memberOf Subscription
235
+ */
236
+ error(error) {
237
+ var self = this;
238
+ if (self._isDeactivated())
239
+ return;
240
+ self._session._stopSubscription(self._subscriptionId, error);
241
+ }
242
+ // Note that while our DDP client will notice that you've called stop() on the
243
+ // server (and clean up its _subscriptions table) we don't actually provide a
244
+ // mechanism for an app to notice this (the subscribe onError callback only
245
+ // triggers if there is an error).
246
+ /**
247
+ * @summary Call inside the publish function. Stops this client's subscription and invokes the client's `onStop` callback with no error.
248
+ * @locus Server
249
+ * @instance
250
+ * @memberOf Subscription
251
+ */
252
+ stop() {
253
+ var self = this;
254
+ if (self._isDeactivated())
255
+ return;
256
+ self._session._stopSubscription(self._subscriptionId);
257
+ }
258
+ /**
259
+ * @summary Call inside the publish function. Registers a callback function to run when the subscription is stopped.
260
+ * @locus Server
261
+ * @memberOf Subscription
262
+ * @instance
263
+ * @param {Function} func The callback function
264
+ */
265
+ onStop(func) {
266
+ var self = this;
267
+ if (self._isDeactivated())
268
+ func();
269
+ else
270
+ self._stopCallbacks.push(func);
271
+ }
272
+ // This returns true if the sub has been deactivated, *OR* if the session was
273
+ // destroyed but the deferred call to _deactivateAllSubscriptions hasn't
274
+ // happened yet.
275
+ _isDeactivated() {
276
+ var self = this;
277
+ return self._deactivated || self._session.inQueue === null;
278
+ }
279
+ initialAdds(collectionName, documents) {
280
+ if (this._isDeactivated())
281
+ return;
282
+ if (this._session.server.getPublicationStrategy(collectionName).doAccountingForCollection) {
283
+ let ids = this._documents.get(collectionName);
284
+ if (ids == null) {
285
+ ids = new Set();
286
+ this._documents.set(collectionName, ids);
287
+ }
288
+ documents.forEach((_doc, id) => ids.add(id));
289
+ }
290
+ if (this._session.version === "1a")
291
+ this._session.initialAdds(this._subscriptionHandle, collectionName, documents);
292
+ else
293
+ documents.forEach((doc, id) => this._session.added(this._subscriptionHandle, collectionName, id, doc));
294
+ }
295
+ /**
296
+ * @summary Call inside the publish function. Informs the subscriber that a document has been added to the record set.
297
+ * @locus Server
298
+ * @memberOf Subscription
299
+ * @instance
300
+ * @param {String} collection The name of the collection that contains the new document.
301
+ * @param {String} id The new document's ID.
302
+ * @param {Object} fields The fields in the new document. If `_id` is present it is ignored.
303
+ */
304
+ added(collectionName, id, fields) {
305
+ if (this._isDeactivated())
306
+ return;
307
+ id = this._idFilter.idStringify(id);
308
+ if (this._session.server.getPublicationStrategy(collectionName).doAccountingForCollection) {
309
+ let ids = this._documents.get(collectionName);
310
+ if (ids == null) {
311
+ ids = new Set();
312
+ this._documents.set(collectionName, ids);
313
+ }
314
+ ids.add(id);
315
+ }
316
+ this._session.added(this._subscriptionHandle, collectionName, id, fields);
317
+ }
318
+ /**
319
+ * @summary Call inside the publish function. Informs the subscriber that a document in the record set has been modified.
320
+ * @locus Server
321
+ * @memberOf Subscription
322
+ * @instance
323
+ * @param {String} collection The name of the collection that contains the changed document.
324
+ * @param {String} id The changed document's ID.
325
+ * @param {Object} fields The fields in the document that have changed, together with their new values. If a field is not present in `fields` it was left unchanged; if it is present in `fields` and has a value of `undefined` it was removed from the document. If `_id` is present it is ignored.
326
+ */
327
+ changed(collectionName, id, fields) {
328
+ if (this._isDeactivated())
329
+ return;
330
+ id = this._idFilter.idStringify(id);
331
+ this._session.changed(this._subscriptionHandle, collectionName, id, fields);
332
+ }
333
+ /**
334
+ * @summary Call inside the publish function. Informs the subscriber that a document has been removed from the record set.
335
+ * @locus Server
336
+ * @memberOf Subscription
337
+ * @instance
338
+ * @param {String} collection The name of the collection that the document has been removed from.
339
+ * @param {String} id The ID of the document that has been removed.
340
+ */
341
+ removed(collectionName, id) {
342
+ if (this._isDeactivated())
343
+ return;
344
+ id = this._idFilter.idStringify(id);
345
+ if (this._session.server.getPublicationStrategy(collectionName).doAccountingForCollection) {
346
+ // We don't bother to delete sets of things in a collection if the
347
+ // collection is empty. It could break _removeAllDocuments.
348
+ this._documents.get(collectionName).delete(id);
349
+ }
350
+ this._session.removed(this._subscriptionHandle, collectionName, id);
351
+ }
352
+ /**
353
+ * @summary Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the `onReady` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any.
354
+ * @locus Server
355
+ * @memberOf Subscription
356
+ * @instance
357
+ */
358
+ ready() {
359
+ var self = this;
360
+ if (self._isDeactivated())
361
+ return;
362
+ if (!self._subscriptionId)
363
+ return; // Unnecessary but ignored for universal sub
364
+ if (!self._ready) {
365
+ self._session.sendReady([self._subscriptionId]);
366
+ self._ready = true;
367
+ }
368
+ }
369
+ }
370
+ exports.Subscription = Subscription;