entangld 2.1.6 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -145,6 +145,7 @@ Any object can store values. And a Map can store values keyed to objects. But
145
145
  - Have your store synchronized with multiple data sources (other stores)?
146
146
  - Over a network?
147
147
  - Subscribe to events within the datastore?
148
+ - Support subscription wildcards?
148
149
 
149
150
  ## Notes
150
151
 
@@ -178,6 +179,15 @@ If these two issues can be resolved at some point, _deref_mode will probably be
178
179
  ## Classes
179
180
 
180
181
  <dl>
182
+ <dt><a href="#Entangld">Entangld</a> ⇐ <code>EventEmitter</code></dt>
183
+ <dd><p>Synchronized Event Store</p>
184
+ </dd>
185
+ <dt><a href="#EntangldError">EntangldError</a></dt>
186
+ <dd><p>Error class for Entangld.</p>
187
+ </dd>
188
+ <dt><a href="#RPCError">RPCError</a></dt>
189
+ <dd><p>Remote Error class for Entangld.</p>
190
+ </dd>
181
191
  <dt><a href="#Entangld_Message">Entangld_Message</a></dt>
182
192
  <dd><p>Message class for Entangld.</p>
183
193
  <p>These messages are used for executing datastore operations between
@@ -191,7 +201,8 @@ downstream datastores do not necessarilly have access to the upstream store
191
201
  structure, and so cannot generally construct upstream paths. This means that
192
202
  the <code>.path</code> attribute is a <code>tree</code> relative to the upstream datastore, and
193
203
  the upstream path can be reconstructed as:</p>
194
- <pre><code class="language-javascript"> &gt; upstream._namespaces.get(downstream) + &quot;.&quot; + msg.path;</code></pre>
204
+ <pre><code class="language-javascript"> &gt; upstream._namespaces.get(downstream) + &quot;.&quot; + msg.path;
205
+ </code></pre>
195
206
  <p>Since <code>unsubscribe</code> messages can pass either upstream or downstream, the notion
196
207
  of a path is ill-defined, and so unsubscribe messages should have their <code>.path</code>
197
208
  attributes set to undefined or null.</p>
@@ -202,621 +213,679 @@ callback functions to be trigger properly, and for unsubscribe messages to
202
213
  propogate both directions. <code>set</code>/<code>push</code> messages do not use the <code>.uuid</code> attribute
203
214
  since they require no response.</p>
204
215
  </dd>
205
- <dt><a href="#EntangldError">EntangldError</a></dt>
206
- <dd><p>Error class for Entangld.</p>
207
- </dd>
208
216
  <dt><a href="#Subscription">Subscription</a></dt>
209
217
  <dd><p>A datastore subscription object</p>
210
218
  </dd>
211
- <dt><a href="#Entangld">Entangld</a> ⇐ <code>EventEmitter</code></dt>
212
- <dd><p>Synchronized Event Store</p>
213
- </dd>
214
219
  </dl>
215
220
 
216
- <a name="Entangld_Message"></a>
217
-
218
- ## Entangld\_Message
219
- Message class for Entangld.
220
-
221
- These messages are used for executing datastore operations between
222
- remote datastores. In these relationships, there is always an upstream
223
- and downstream pair, so that `get`, `set`, `push` and `subscribe` messages
224
- are created upstream and passed downstream while `event` and `value` messages
225
- are created downstream and are passed back up. `unsubscribe` events can travel
226
- in both directions. To maintain consistency, the internal `.path` attribute
227
- will always refer a path relative to the downstream datastore, since the
228
- downstream datastores do not necessarilly have access to the upstream store
229
- structure, and so cannot generally construct upstream paths. This means that
230
- the `.path` attribute is a `tree` relative to the upstream datastore, and
231
- the upstream path can be reconstructed as:
232
- ```javascript
233
- > upstream._namespaces.get(downstream) + "." + msg.path;
234
- ```
235
- Since `unsubscribe` messages can pass either upstream or downstream, the notion
236
- of a path is ill-defined, and so unsubscribe messages should have their `.path`
237
- attributes set to undefined or null.
221
+ <a name="Entangld"></a>
238
222
 
239
- Most messages will also have a `.uuid` attribute. For `get`/`value` messages,
240
- this allows for the value to be properly linked back up with the original `get`
241
- message. For the `subscribe`/`unsubscribe`/`event` messages, this allows for
242
- callback functions to be trigger properly, and for unsubscribe messages to
243
- propogate both directions. `set`/`push` messages do not use the `.uuid` attribute
244
- since they require no response.
223
+ ## Entangld ⇐ <code>EventEmitter</code>
224
+ Synchronized Event Store
245
225
 
246
226
  **Kind**: global class
227
+ **Extends**: <code>EventEmitter</code>
247
228
 
248
- * [Entangld_Message](#Entangld_Message)
249
- * [.get(tree, [get_params])](#Entangld_Message.get) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
250
- * [.value(get_msg, value)](#Entangld_Message.value) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
251
- * [.setpush(obj)](#Entangld_Message.setpush) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
252
- * [.subscribe(tree, uuid)](#Entangld_Message.subscribe) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
253
- * [.event(path, value, uuid)](#Entangld_Message.event) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
254
- * [.unsubscribe(uuid)](#Entangld_Message.unsubscribe)
229
+ * [Entangld](#Entangld) ⇐ <code>EventEmitter</code>
230
+ * [.namespaces](#Entangld+namespaces) ⇒ <code>array</code>
231
+ * [.subscriptions](#Entangld+subscriptions) ⇒ [<code>Array.&lt;Subscription&gt;</code>](#Subscription)
232
+ * [.namespace()](#Entangld+namespace) ⇒ <code>string</code>
233
+ * [.attach(namespace, obj)](#Entangld+attach)
234
+ * [.detach([namespace], [obj])](#Entangld+detach) ⇒ <code>boolean</code>
235
+ * [.transmit(func)](#Entangld+transmit)
236
+ * [.receive(msg, obj)](#Entangld+receive)
237
+ * [.push(path, data, [limit])](#Entangld+push)
238
+ * [.set(path, data, [operation_type], [params])](#Entangld+set)
239
+ * [.set_rpc(path, func, opts)](#Entangld+set_rpc)
240
+ * [.set_rpc_class(object, key_description_pairs, opts)](#Entangld+set_rpc_class)
241
+ * [.call_rpc(path, [args])](#Entangld+call_rpc) ⇒ <code>Promise</code>
242
+ * [.get(path, [params])](#Entangld+get) ⇒ <code>Promise</code>
243
+ * [.subscribe(path, func, [every])](#Entangld+subscribe) ⇒ <code>uuidv4</code>
244
+ * [.subscribed_to(subscription)](#Entangld+subscribed_to) ⇒ <code>Boolean</code>
245
+ * [.unsubscribe(path_or_uuid)](#Entangld+unsubscribe) ⇒ <code>number</code>
246
+ * [.unsubscribe_tree(path)](#Entangld+unsubscribe_tree)
255
247
 
256
- <a name="Entangld_Message.get"></a>
248
+ <a name="Entangld+namespaces"></a>
257
249
 
258
- ### Entangld_Message.get(tree, [get_params]) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
259
- Create a `get` message for remote datastores
250
+ ### entangld.namespaces ⇒ <code>array</code>
251
+ Get namespaces
260
252
 
261
- **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
262
- **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - - The get message to pass to the remote datastore
253
+ **Kind**: instance property of [<code>Entangld</code>](#Entangld)
254
+ **Returns**: <code>array</code> - namespaces - an array of attached namespaces
255
+ **Read only**: true
256
+ <a name="Entangld+subscriptions"></a>
263
257
 
264
- | Param | Type | Description |
265
- | --- | --- | --- |
266
- | tree | <code>string</code> | the path relative to the remote datastore |
267
- | [get_params] | <code>\*</code> | any parameters to be passed to the remote datastore's local get function |
258
+ ### entangld.subscriptions ⇒ [<code>Array.&lt;Subscription&gt;</code>](#Subscription)
259
+ Get list of subscriptions associated with this object
268
260
 
269
- <a name="Entangld_Message.value"></a>
261
+ Note, this will include `head`, `terminal` and `pass through` subscriptions,
262
+ which can be checked using getter methods of the subscription object.
270
263
 
271
- ### Entangld_Message.value(get_msg, value) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
272
- Create a `value` message in response to a `get` message
264
+ **Kind**: instance property of [<code>Entangld</code>](#Entangld)
265
+ **Returns**: [<code>Array.&lt;Subscription&gt;</code>](#Subscription) - array of Subscriptions associated with this object
266
+ **Read only**: true
267
+ <a name="Entangld+namespace"></a>
273
268
 
274
- **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
275
- **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - - The `value` message to pass back
269
+ ### entangld.namespace() ⇒ <code>string</code>
270
+ Get namespace for a store
276
271
 
277
- | Param | Type | Description |
278
- | --- | --- | --- |
279
- | get_msg | [<code>Entangld\_Message</code>](#Entangld_Message) | the `get` message which this is in response to |
280
- | value | | the value of the `get` |
272
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
273
+ **Returns**: <code>string</code> - namespace for the given store
274
+ **Read only**: true
275
+ <a name="Entangld+attach"></a>
281
276
 
282
- <a name="Entangld_Message.setpush"></a>
277
+ ### entangld.attach(namespace, obj)
278
+ Attach a namespace and a store
283
279
 
284
- ### Entangld_Message.setpush(obj) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
285
- Create a `set`/`push` message for a remote datastore
280
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
281
+ **Throws**:
282
+
283
+ - <code>TypeError</code> if namespace/obj is null or empty.
284
+ - [<code>EntangldError</code>](#EntangldError) if you try to attach to the same namespace twice.
286
285
 
287
- **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
288
- **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - - the "set" or "push" message
289
286
 
290
287
  | Param | Type | Description |
291
288
  | --- | --- | --- |
292
- | obj | <code>Object</code> | The parameter object for the set/push |
293
- | obj.type | <code>string</code> | either "set" or "push" |
294
- | obj.tree | <code>string</code> | the path (relative to the downstream datastore) |
295
- | obj.value | <code>\*</code> | the value to insert into the datastore |
296
- | obj.params | <code>\*</code> | any additional parameters |
297
-
298
- <a name="Entangld_Message.subscribe"></a>
289
+ | namespace | <code>string</code> | a namespace for this store. |
290
+ | obj | <code>object</code> | an object that will be sent along with "transmit" callbacks when we need something from this store. |
299
291
 
300
- ### Entangld_Message.subscribe(tree, uuid) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
301
- Construct subscribe message
292
+ <a name="Entangld+detach"></a>
302
293
 
303
- **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
304
- **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - the `subscribe` message
294
+ ### entangld.detach([namespace], [obj]) ⇒ <code>boolean</code>
295
+ Detach a namespace / obj pair.
305
296
 
306
- | Param | Type | Description |
307
- | --- | --- | --- |
308
- | tree | <code>string</code> | the path (relative to the downstream datastore) |
309
- | uuid | <code>Uuid</code> | the subscription uuid |
297
+ If you only pass a namespace or a store, it will find the missing item
298
+ before detaching.
310
299
 
311
- <a name="Entangld_Message.event"></a>
300
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
301
+ **Returns**: <code>boolean</code> - true if the element existed and was removed.
302
+ **Throws**:
312
303
 
313
- ### Entangld_Message.event(path, value, uuid) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
314
- Create an `event` message to return data to subscribe callbacks
304
+ - [<code>EntangldError</code>](#EntangldError) Error will be thrown if you don't pass at least
305
+ one parameter.
315
306
 
316
- **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
317
- **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - the `event` message
318
307
 
319
308
  | Param | Type | Description |
320
309
  | --- | --- | --- |
321
- | path | <code>string</code> | the path (relative to the downstream store) |
322
- | value | <code>\*</code> | the updated datastore value at the path |
323
- | uuid | <code>Uuid</code> | the uuid of the subscribe being triggered |
310
+ | [namespace] | <code>string</code> | the namespace. |
311
+ | [obj] | <code>object</code> | the store object. |
324
312
 
325
- <a name="Entangld_Message.unsubscribe"></a>
313
+ <a name="Entangld+transmit"></a>
326
314
 
327
- ### Entangld_Message.unsubscribe(uuid)
328
- Create an unsubscribe message for a subscription uuid
315
+ ### entangld.transmit(func)
316
+ Transmit
329
317
 
330
- **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
318
+ Specify a callback to be used so we can transmit data to another store.
319
+ Callback will be passed (message, obj) where 'message' is an
320
+ Entangld_Message object and obj is the object provided by attach().
331
321
 
332
- | Param | Type | Description |
333
- | --- | --- | --- |
334
- | uuid | <code>String</code> | the subscription uuid |
322
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
323
+ **Throws**:
335
324
 
336
- <a name="EntangldError"></a>
325
+ - <code>TypeError</code> if func is not a function.
337
326
 
338
- ## EntangldError
339
- Error class for Entangld.
340
327
 
341
- **Kind**: global class
342
- <a name="Subscription"></a>
328
+ | Param | Type | Description |
329
+ | --- | --- | --- |
330
+ | func | <code>function</code> | the callback function. |
343
331
 
344
- ## Subscription
345
- A datastore subscription object
332
+ <a name="Entangld+receive"></a>
346
333
 
347
- **Kind**: global class
334
+ ### entangld.receive(msg, obj)
335
+ Receive
348
336
 
349
- * [Subscription](#Subscription)
350
- * [new Subscription(obj)](#new_Subscription_new)
351
- * [.is_pass_through](#Subscription+is_pass_through) ⇒ <code>Boolean</code>
352
- * [.is_terminal](#Subscription+is_terminal) ⇒ <code>Boolean</code>
353
- * [.is_head](#Subscription+is_head) ⇒ <code>Boolean</code>
354
- * [.has_downstream](#Subscription+has_downstream) ⇒ <code>Boolean</code>
355
- * [.has_upstream](#Subscription+has_upstream) ⇒ <code>Boolean</code>
356
- * [.call()](#Subscription+call)
357
- * [.matches_subscription(sub)](#Subscription+matches_subscription) ⇒ <code>Boolean</code>
358
- * [.matches_event_message(msg)](#Subscription+matches_event_message) ⇒ <code>Boolean</code>
359
- * [.matches_unsubscribe_message(msg)](#Subscription+matches_unsubscribe_message) ⇒ <code>Boolean</code>
360
- * [.matches_path(path)](#Subscription+matches_path) ⇒ <code>Boolean</code>
361
- * [.matches_uuid(uuid)](#Subscription+matches_uuid) ⇒ <code>Boolean</code>
362
- * [.is_beneath(path)](#Subscription+is_beneath) ⇒ <code>Boolean</code>
363
- * [.is_above(path)](#Subscription+is_above) ⇒ <code>Boolean</code>
364
- * [.static_copy()](#Subscription+static_copy) ⇒ [<code>Subscription</code>](#Subscription)
337
+ Call this function with the data that was sent via the transmit()
338
+ callback.
365
339
 
366
- <a name="new_Subscription_new"></a>
340
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
341
+ **Throws**:
367
342
 
368
- ### new Subscription(obj)
369
- Constructor
343
+ - <code>ReferenceError</code> if event object was not provided.
344
+ - [<code>EntangldError</code>](#EntangldError) if an unknown message type was received.
370
345
 
371
- **Returns**: [<code>Subscription</code>](#Subscription) - - the subscription object
372
346
 
373
347
  | Param | Type | Description |
374
348
  | --- | --- | --- |
375
- | obj | <code>Object</code> | the configuration object |
376
- | obj.path | <code>string</code> | the datastore path (relative to this datastore) of the subscription |
377
- | obj.uuid | <code>Uuid</code> | the uuid of the subscription chain |
378
- | obj.callback | <code>function</code> | the callback function, with signature (path, value), where path is relative to this datastore |
379
- | obj.downstream | [<code>Entangld</code>](#Entangld) \| <code>null</code> | the downstream datastore (if any) associated with this subscription |
380
- | obj.upstream | [<code>Entangld</code>](#Entangld) \| <code>null</code> | the upstream datastore (if any) associated with this subscription |
381
- | obj.every | <code>number</code> \| <code>null</code> | how many `set` messages to wait before calling callback |
349
+ | msg | [<code>Entangld\_Message</code>](#Entangld_Message) | the message to process. |
350
+ | obj | <code>object</code> | the attach() object where the message originted. |
382
351
 
383
- <a name="Subscription+is_pass_through"></a>
352
+ <a name="Entangld+push"></a>
384
353
 
385
- ### subscription.is\_pass\_through ⇒ <code>Boolean</code>
386
- Check if subscription is a `pass through` type
354
+ ### entangld.push(path, data, [limit])
355
+ Push an object into an array in the store.
387
356
 
388
- Pass throughs are as the links in a chain of subscriptions to allows
389
- subscriptions to remote datastores. One store acts as the `head`, where
390
- the callback function is registered, an all others are `path through` datastores
391
- which simply pass event messages back up to the head subscription.
357
+ Convenience method for set(path, o, "push").
392
358
 
393
- **Kind**: instance property of [<code>Subscription</code>](#Subscription)
394
- <a name="Subscription+is_terminal"></a>
359
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
360
+ **Throws**:
395
361
 
396
- ### subscription.is\_terminal ⇒ <code>Boolean</code>
397
- Check if this subscription will be directly given data by a datastore
362
+ - <code>TypeError</code> if path is not a string.
398
363
 
399
- **Kind**: instance property of [<code>Subscription</code>](#Subscription)
400
- <a name="Subscription+is_head"></a>
401
364
 
402
- ### subscription.is\_head ⇒ <code>Boolean</code>
403
- Check if this subscription will apply a user-supplied callback to data
365
+ | Param | Type | Default | Description |
366
+ | --- | --- | --- | --- |
367
+ | path | <code>string</code> | | the path to set (like "system.fan.voltage"). |
368
+ | data | <code>object</code> | | the object or function you want to store at path. |
369
+ | [limit] | <code>number</code> | <code></code> | maximum size of the array. Older entries will be removed until the array size is less than or equal to limit. |
404
370
 
405
- **Kind**: instance property of [<code>Subscription</code>](#Subscription)
406
- <a name="Subscription+has_downstream"></a>
371
+ <a name="Entangld+set"></a>
407
372
 
408
- ### subscription.has\_downstream ⇒ <code>Boolean</code>
409
- Check if subscription has any downstream subscriptions
373
+ ### entangld.set(path, data, [operation_type], [params])
374
+ Set an object into the store
410
375
 
411
- It the subscription refers to a remote datastore (the downstream), this
412
- getter will return a true. Note that !this.has_downstream will check if
413
- the subscription is the `tail` subscription object in a subscription chain.
376
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
377
+ **Throws**:
414
378
 
415
- **Kind**: instance property of [<code>Subscription</code>](#Subscription)
416
- <a name="Subscription+has_upstream"></a>
417
-
418
- ### subscription.has\_upstream ⇒ <code>Boolean</code>
419
- Check if subscription has any upstream subscriptions
420
-
421
- It the subscription passes data back to a remote datastore (the upstream), this
422
- getter will return a true.
423
-
424
- **Kind**: instance property of [<code>Subscription</code>](#Subscription)
425
- <a name="Subscription+call"></a>
426
-
427
- ### subscription.call()
428
- Apply this callback function
429
-
430
- Note, this method also tracks the number of times that a callback
431
- function is called (if this subscription is terminal), so that if
432
- the subscriptions are throttled by specifying an `this.every`,
433
- this method will only call the callback function every `this.every`
434
- times it receives a `set` message. If this subscription is not
435
- terminal, then the callback function is called every time.
436
-
437
- This method also is safed when a callback function is not give (i.e.
438
- by the `this.static_copy()` method).
439
-
440
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
441
- <a name="Subscription+matches_subscription"></a>
379
+ - <code>TypeError</code> if path is not a string.
442
380
 
443
- ### subscription.matches\_subscription(sub) ⇒ <code>Boolean</code>
444
- Check if a different `Subscription` object matches this subscription
445
381
 
446
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
447
- **Returns**: <code>Boolean</code> - - True if the subscriptions match
382
+ | Param | Type | Default | Description |
383
+ | --- | --- | --- | --- |
384
+ | path | <code>string</code> | | the path to set (like "system.fan.voltage"). |
385
+ | data | <code>object</code> | | the object or function you want to store at path. |
386
+ | [operation_type] | <code>string</code> | <code>&quot;\&quot;set\&quot;&quot;</code> | whether to set or push the new data (push only works if the data item exists and is an array). |
387
+ | [params] | <code>object</code> | | additional parameters. |
448
388
 
449
- | Param | Type | Description |
450
- | --- | --- | --- |
451
- | sub | [<code>Subscription</code>](#Subscription) | a different subscription |
389
+ <a name="Entangld+set_rpc"></a>
452
390
 
453
- <a name="Subscription+matches_event_message"></a>
391
+ ### entangld.set\_rpc(path, func, opts)
392
+ Set a function as an RPC in the datastore
454
393
 
455
- ### subscription.matches\_event\_message(msg) ⇒ <code>Boolean</code>
456
- Check if an `event` message matches this subscription
394
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
395
+ **Throws**:
457
396
 
458
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
459
- **Returns**: <code>Boolean</code> - - True if the message is associated with the subscription
397
+ - <code>TypeError</code> if path is not a string.
460
398
 
461
- | Param | Type | Description |
462
- | --- | --- | --- |
463
- | msg | [<code>Entangld\_Message</code>](#Entangld_Message) | a received message from a downstream datastore |
464
399
 
465
- <a name="Subscription+matches_unsubscribe_message"></a>
400
+ | Param | Type | Default | Description |
401
+ | --- | --- | --- | --- |
402
+ | path | <code>string</code> | | the path to set (like "system.fan.voltage"). |
403
+ | func | <code>function</code> | | the function you want to store at path. |
404
+ | opts | <code>object</code> | | |
405
+ | [opts.description] | <code>string</code> | <code>null</code> | description for the function |
406
+ | [opts.function_string] | <code>string</code> | <code>null</code> | optional string of function source code to pass to parameter_parser |
466
407
 
467
- ### subscription.matches\_unsubscribe\_message(msg) ⇒ <code>Boolean</code>
468
- Check if an `unsubscribe` message matches this subscription
408
+ <a name="Entangld+set_rpc_class"></a>
469
409
 
470
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
471
- **Returns**: <code>Boolean</code> - - True if the message is associated with the subscription
410
+ ### entangld.set\_rpc\_class(object, key_description_pairs, opts)
411
+ Set a class instance as an RPC object in the datastore
472
412
 
473
- | Param | Type | Description |
474
- | --- | --- | --- |
475
- | msg | [<code>Entangld\_Message</code>](#Entangld_Message) | a received message from a downstream datastore |
413
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
414
+ **Throws**:
476
415
 
477
- <a name="Subscription+matches_path"></a>
416
+ - <code>TypeError</code> if path is not a string.
478
417
 
479
- ### subscription.matches\_path(path) ⇒ <code>Boolean</code>
480
- Check if a provided path matches this path
481
418
 
482
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
483
- **Returns**: <code>Boolean</code> - - true if the path matches
419
+ | Param | Type | Default | Description |
420
+ | --- | --- | --- | --- |
421
+ | object | <code>\*</code> | | The object to attach |
422
+ | key_description_pairs | <code>Array</code> | | An array of key, description pairs |
423
+ | opts | <code>object</code> | | |
424
+ | [opts.description] | <code>string</code> | <code>null</code> | description for the function |
425
+ | [opts.function_string] | <code>string</code> | <code>null</code> | optional string of function source code to pass to parameter_parser |
484
426
 
485
- | Param | Type | Description |
486
- | --- | --- | --- |
487
- | path | <code>String</code> | a path string to check against |
427
+ <a name="Entangld+call_rpc"></a>
488
428
 
489
- <a name="Subscription+matches_uuid"></a>
429
+ ### entangld.call\_rpc(path, [args]) ⇒ <code>Promise</code>
430
+ Call an RPC procedure in the datastore
490
431
 
491
- ### subscription.matches\_uuid(uuid) ⇒ <code>Boolean</code>
492
- Check if a provided uuid matches this uuid
432
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
433
+ **Returns**: <code>Promise</code> - promise resolving to return value of the rpc
434
+ **Throws**:
493
435
 
494
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
495
- **Returns**: <code>Boolean</code> - - true if the path matches
436
+ - [<code>RPCError</code>](#RPCError) if the rpc call experienced an error
496
437
 
497
- | Param | Type | Description |
498
- | --- | --- | --- |
499
- | uuid | <code>Uuid</code> | a uuid string to check against |
500
438
 
501
- <a name="Subscription+is_beneath"></a>
439
+ | Param | Type | Default | Description |
440
+ | --- | --- | --- | --- |
441
+ | path | <code>string</code> | | the path to query (like "system.voltage"). |
442
+ | [args] | <code>Array</code> | <code>[]</code> | the arguments to pass to the RPC. |
502
443
 
503
- ### subscription.is\_beneath(path) ⇒ <code>Boolean</code>
504
- Check if subscription path is beneath a provided path
444
+ <a name="Entangld+get"></a>
505
445
 
506
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
507
- **Returns**: <code>Boolean</code> - - true if the subscription is beneath the path
446
+ ### entangld.get(path, [params]) ⇒ <code>Promise</code>
447
+ Get an object from the store.
508
448
 
509
- | Param | Type | Description |
510
- | --- | --- | --- |
511
- | path | <code>String</code> | a path string to check against |
449
+ Note: using max_depth, especially large max_depth, involves a lot of
450
+ recursion and may be expensive.
512
451
 
513
- <a name="Subscription+is_above"></a>
452
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
453
+ **Returns**: <code>Promise</code> - promise resolving to the object at that path.
454
+ **Throws**:
514
455
 
515
- ### subscription.is\_above(path) ⇒ <code>Boolean</code>
516
- Check if subscription path is above a provided path
456
+ - <code>TypeError</code> if path is not a string.
517
457
 
518
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
519
- **Returns**: <code>Boolean</code> - - true if the subscription is beneath the path
520
458
 
521
459
  | Param | Type | Description |
522
460
  | --- | --- | --- |
523
- | path | <code>String</code> | a path string to check against |
524
-
525
- <a name="Subscription+static_copy"></a>
526
-
527
- ### subscription.static\_copy() ⇒ [<code>Subscription</code>](#Subscription)
528
- Get a copy of this subscription without external references
529
-
530
- This creates a copy, except the upstream/downstream references
531
- are set to true (if they exist) or null (if they don't. Addtionally,
532
- the callback function is excluded.
461
+ | path | <code>string</code> | the path to query (like "system.voltage"). |
462
+ | [params] | <code>object</code> | the parameters to be passed to the remote function (RPC) or the maximum depth of the returned object (normal mode). |
533
463
 
534
- **Kind**: instance method of [<code>Subscription</code>](#Subscription)
535
- **Returns**: [<code>Subscription</code>](#Subscription) - a copy of this subscription object
536
- <a name="Entangld"></a>
464
+ <a name="Entangld+subscribe"></a>
537
465
 
538
- ## Entangld ⇐ <code>EventEmitter</code>
539
- Synchronized Event Store
466
+ ### entangld.subscribe(path, func, [every]) ⇒ <code>uuidv4</code>
467
+ Subscribe to change events for a path
540
468
 
541
- **Kind**: global class
542
- **Extends**: <code>EventEmitter</code>
469
+ If objects at or below this path change, you will get a callback
543
470
 
544
- * [Entangld](#Entangld) ⇐ <code>EventEmitter</code>
545
- * [.namespaces](#Entangld+namespaces) ⇒ <code>array</code>
546
- * [.subscriptions](#Entangld+subscriptions) ⇒ [<code>Array.&lt;Subscription&gt;</code>](#Subscription)
547
- * [.namespace()](#Entangld+namespace) ⇒ <code>string</code>
548
- * [.attach(namespace, obj)](#Entangld+attach)
549
- * [.detach([namespace], [obj])](#Entangld+detach) ⇒ <code>boolean</code>
550
- * [.transmit(func)](#Entangld+transmit)
551
- * [.receive(msg, obj)](#Entangld+receive)
552
- * [.push(path, data, [limit])](#Entangld+push)
553
- * [.set(path, data, [operation_type], [params])](#Entangld+set)
554
- * [.get(path, [params])](#Entangld+get) ⇒ <code>Promise</code>
555
- * [.subscribe(path, func, [every])](#Entangld+subscribe) ⇒ <code>Uuid</code>
556
- * [.subscribed_to(subscription)](#Entangld+subscribed_to) ⇒ <code>Boolean</code>
557
- * [.unsubscribe(path_or_uuid)](#Entangld+unsubscribe) ⇒ <code>number</code>
558
- * [.unsubscribe_tree(path)](#Entangld+unsubscribe_tree)
471
+ Subscriptions to keys within attach()ed stores are remote subscriptions.
472
+ If several stores are attached in some kind of arrangement, a given key
473
+ may actually traverse multiple stores! Since each store only knows its
474
+ immediate neighbors - and has no introspection into those neighbors - each
475
+ store is only able to keeps track of the neighbor on each side with
476
+ respect to a particular path and has no knowledge of the eventual
477
+ endpoints. This means that subscribing across several datstores is accomplished
478
+ by daisy-chaining 2-way subscriptions across each datastore interface.
559
479
 
560
- <a name="Entangld+namespaces"></a>
480
+ For example, let's suppose capital letters represent Entangld stores and
481
+ lowercase letters are actual objects. Then the path "A.B.c.d.E.F.g.h"
482
+ will represent a subscription that traverses four Entangld stores.
483
+ From the point of view of a store in the middle - say, E - the "upstream"
484
+ is B and the "downstream" is F.
561
485
 
562
- ### entangld.namespaces ⇒ <code>array</code>
563
- Get namespaces
486
+ Each store involved keeps track of any subscriptions with which it is
487
+ involved. It tracks the upstream and downstream, and the uuid of the
488
+ subscription. The uuid is the same across all stores for a given
489
+ subscription. For a particular store, the upstream is null if it is the
490
+ original link in the chain (called the `head`), and the downstream is
491
+ null if this store owns the endpoint value (called the `tail`). Any
492
+ subscription which is not the head of a chain is called a `pass through`
493
+ subscription, because it exist only to pass `event` messages back up the
494
+ chain to the head (where the user-provided callback function exists).
495
+ subscriptions can be checked to see if they are `pass through` type via
496
+ the getter `sub.is_pass_through`.
564
497
 
565
- **Kind**: instance property of [<code>Entangld</code>](#Entangld)
566
- **Returns**: <code>array</code> - namespaces - an array of attached namespaces
567
- **Read only**: true
568
- <a name="Entangld+subscriptions"></a>
498
+ **Kind**: instance method of [<code>Entangld</code>](#Entangld)
499
+ **Returns**: <code>uuidv4</code> - - the uuid of the subscription
500
+ **Throws**:
569
501
 
570
- ### entangld.subscriptions ⇒ [<code>Array.&lt;Subscription&gt;</code>](#Subscription)
571
- Get list of subscriptions associated with this object
502
+ - <code>TypeError</code> if path is not a string.
572
503
 
573
- Note, this will include `head`, `terminal` and `pass through` subscriptions,
574
- which can be checked using getter methods of the subscription object.
575
504
 
576
- **Kind**: instance property of [<code>Entangld</code>](#Entangld)
577
- **Returns**: [<code>Array.&lt;Subscription&gt;</code>](#Subscription) - array of Subscriptions associated with this object
578
- **Read only**: true
579
- <a name="Entangld+namespace"></a>
505
+ | Param | Type | Default | Description |
506
+ | --- | --- | --- | --- |
507
+ | path | <code>string</code> | | the path to watch. Use of '*' is allowed as a wildcard (e.g. "system.*") |
508
+ | func | <code>function</code> | | the callback - will be of the form (path, value). |
509
+ | [every] | <code>number</code> \| <code>null</code> | <code></code> | the number of `set` messages to wait before calling callback |
580
510
 
581
- ### entangld.namespace() ⇒ <code>string</code>
582
- Get namespace for a store
511
+ <a name="Entangld+subscribed_to"></a>
583
512
 
584
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
585
- **Returns**: <code>string</code> - namespace for the given store
586
- **Read only**: true
587
- <a name="Entangld+attach"></a>
513
+ ### entangld.subscribed\_to(subscription) ⇒ <code>Boolean</code>
514
+ Check for subscription
588
515
 
589
- ### entangld.attach(namespace, obj)
590
- Attach a namespace and a store
516
+ Are we subscribed to a particular remote path?
591
517
 
592
518
  **Kind**: instance method of [<code>Entangld</code>](#Entangld)
593
- **Throws**:
594
-
595
- - <code>TypeError</code> if namespace/obj is null or empty.
596
- - [<code>EntangldError</code>](#EntangldError) if you try to attach to the same namespace twice.
597
-
519
+ **Returns**: <code>Boolean</code> - true if we are subscribed.
598
520
 
599
521
  | Param | Type | Description |
600
522
  | --- | --- | --- |
601
- | namespace | <code>string</code> | a namespace for this store. |
602
- | obj | <code>object</code> | an object that will be sent along with "transmit" callbacks when we need something from this store. |
523
+ | subscription | <code>String</code> | the subscription to check for. |
603
524
 
604
- <a name="Entangld+detach"></a>
525
+ <a name="Entangld+unsubscribe"></a>
605
526
 
606
- ### entangld.detach([namespace], [obj]) ⇒ <code>boolean</code>
607
- Detach a namespace / obj pair.
527
+ ### entangld.unsubscribe(path_or_uuid) ⇒ <code>number</code>
528
+ Unubscribe to change events for a given path or uuid.
608
529
 
609
- If you only pass a namespace or a store, it will find the missing item
610
- before detaching.
530
+ Caution - if a path is provided, _all_ events belonging to you with that
531
+ path will be deleted, so if you have multiple subscriptions on a single path,
532
+ and only want one of them to be removed, you must provide the uuid instead.
611
533
 
612
534
  **Kind**: instance method of [<code>Entangld</code>](#Entangld)
613
- **Returns**: <code>boolean</code> - true if the element existed and was removed.
535
+ **Returns**: <code>number</code> - count of subscriptions removed.
614
536
  **Throws**:
615
537
 
616
- - [<code>EntangldError</code>](#EntangldError) Error will be thrown if you don't pass at least
617
- one parameter.
538
+ - [<code>EntangldError</code>](#EntangldError) if no subscriptions were found.
618
539
 
619
540
 
620
541
  | Param | Type | Description |
621
542
  | --- | --- | --- |
622
- | [namespace] | <code>string</code> | the namespace. |
623
- | [obj] | <code>object</code> | the store object. |
543
+ | path_or_uuid | <code>String</code> \| <code>uuidv4</code> | the path (or uuid) to unwatch. |
624
544
 
625
- <a name="Entangld+transmit"></a>
545
+ <a name="Entangld+unsubscribe_tree"></a>
626
546
 
627
- ### entangld.transmit(func)
628
- Transmit
547
+ ### entangld.unsubscribe\_tree(path)
548
+ Unsubscribe tree.
629
549
 
630
- Specify a callback to be used so we can transmit data to another store.
631
- Callback will be passed (message, obj) where 'message' is an
632
- Entangld_Message object and obj is the object provided by attach().
550
+ Remove any subscriptions that are beneath a path.
633
551
 
634
552
  **Kind**: instance method of [<code>Entangld</code>](#Entangld)
635
553
  **Throws**:
636
554
 
637
- - <code>TypeError</code> if func is not a function.
555
+ - [<code>EntangldError</code>](#EntangldError) error if there are stores we cannot detach
556
+ (i.e. they belong to someone else / upstream != null)
638
557
 
639
558
 
640
559
  | Param | Type | Description |
641
560
  | --- | --- | --- |
642
- | func | <code>function</code> | the callback function. |
561
+ | path | <code>string</code> | the tree to unwatch. |
643
562
 
644
- <a name="Entangld+receive"></a>
563
+ <a name="EntangldError"></a>
645
564
 
646
- ### entangld.receive(msg, obj)
647
- Receive
565
+ ## EntangldError
566
+ Error class for Entangld.
648
567
 
649
- Call this function with the data that was sent via the transmit()
650
- callback.
568
+ **Kind**: global class
569
+ <a name="RPCError"></a>
651
570
 
652
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
653
- **Throws**:
571
+ ## RPCError
572
+ Remote Error class for Entangld.
654
573
 
655
- - <code>ReferenceError</code> if event object was not provided.
656
- - [<code>EntangldError</code>](#EntangldError) if an unknown message type was received.
574
+ **Kind**: global class
575
+ <a name="Entangld_Message"></a>
576
+
577
+ ## Entangld\_Message
578
+ Message class for Entangld.
579
+
580
+ These messages are used for executing datastore operations between
581
+ remote datastores. In these relationships, there is always an upstream
582
+ and downstream pair, so that `get`, `set`, `push` and `subscribe` messages
583
+ are created upstream and passed downstream while `event` and `value` messages
584
+ are created downstream and are passed back up. `unsubscribe` events can travel
585
+ in both directions. To maintain consistency, the internal `.path` attribute
586
+ will always refer a path relative to the downstream datastore, since the
587
+ downstream datastores do not necessarilly have access to the upstream store
588
+ structure, and so cannot generally construct upstream paths. This means that
589
+ the `.path` attribute is a `tree` relative to the upstream datastore, and
590
+ the upstream path can be reconstructed as:
591
+ ```javascript
592
+ > upstream._namespaces.get(downstream) + "." + msg.path;
593
+ ```
594
+ Since `unsubscribe` messages can pass either upstream or downstream, the notion
595
+ of a path is ill-defined, and so unsubscribe messages should have their `.path`
596
+ attributes set to undefined or null.
597
+
598
+ Most messages will also have a `.uuid` attribute. For `get`/`value` messages,
599
+ this allows for the value to be properly linked back up with the original `get`
600
+ message. For the `subscribe`/`unsubscribe`/`event` messages, this allows for
601
+ callback functions to be trigger properly, and for unsubscribe messages to
602
+ propogate both directions. `set`/`push` messages do not use the `.uuid` attribute
603
+ since they require no response.
604
+
605
+ **Kind**: global class
657
606
 
607
+ * [Entangld_Message](#Entangld_Message)
608
+ * [.get(tree, [get_params])](#Entangld_Message.get) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
609
+ * [.value(get_msg, value)](#Entangld_Message.value) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
610
+ * [.setpush(obj)](#Entangld_Message.setpush) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
611
+ * [.subscribe(tree, uuid)](#Entangld_Message.subscribe) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
612
+ * [.event(path, value, uuid)](#Entangld_Message.event) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
613
+ * [.unsubscribe(uuid)](#Entangld_Message.unsubscribe)
614
+
615
+ <a name="Entangld_Message.get"></a>
616
+
617
+ ### Entangld_Message.get(tree, [get_params]) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
618
+ Create a `get` message for remote datastores
619
+
620
+ **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
621
+ **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - - The get message to pass to the remote datastore
658
622
 
659
623
  | Param | Type | Description |
660
624
  | --- | --- | --- |
661
- | msg | [<code>Entangld\_Message</code>](#Entangld_Message) | the message to process. |
662
- | obj | <code>object</code> | the attach() object where the message originted. |
625
+ | tree | <code>string</code> | the path relative to the remote datastore |
626
+ | [get_params] | <code>\*</code> | any parameters to be passed to the remote datastore's local get function |
663
627
 
664
- <a name="Entangld+push"></a>
628
+ <a name="Entangld_Message.value"></a>
665
629
 
666
- ### entangld.push(path, data, [limit])
667
- Push an object into an array in the store.
630
+ ### Entangld_Message.value(get_msg, value) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
631
+ Create a `value` message in response to a `get` message
668
632
 
669
- Convenience method for set(path, o, "push").
633
+ **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
634
+ **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - - The `value` message to pass back
670
635
 
671
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
672
- **Throws**:
636
+ | Param | Type | Description |
637
+ | --- | --- | --- |
638
+ | get_msg | [<code>Entangld\_Message</code>](#Entangld_Message) | the `get` message which this is in response to |
639
+ | value | | the value of the `get` |
673
640
 
674
- - <code>TypeError</code> if path is not a string.
641
+ <a name="Entangld_Message.setpush"></a>
675
642
 
643
+ ### Entangld_Message.setpush(obj) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
644
+ Create a `set`/`push` message for a remote datastore
676
645
 
677
- | Param | Type | Default | Description |
678
- | --- | --- | --- | --- |
679
- | path | <code>string</code> | | the path to set (like "system.fan.voltage"). |
680
- | data | <code>object</code> | | the object or function you want to store at path. |
681
- | [limit] | <code>number</code> | <code></code> | maximum size of the array. Older entries will be removed until the array size is less than or equal to limit. |
646
+ **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
647
+ **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - - the "set" or "push" message
682
648
 
683
- <a name="Entangld+set"></a>
649
+ | Param | Type | Description |
650
+ | --- | --- | --- |
651
+ | obj | <code>Object</code> | The parameter object for the set/push |
652
+ | obj.type | <code>string</code> | either "set" or "push" |
653
+ | obj.tree | <code>string</code> | the path (relative to the downstream datastore) |
654
+ | obj.value | <code>\*</code> | the value to insert into the datastore |
655
+ | obj.params | <code>\*</code> | any additional parameters |
684
656
 
685
- ### entangld.set(path, data, [operation_type], [params])
686
- Set an object into the store
657
+ <a name="Entangld_Message.subscribe"></a>
687
658
 
688
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
689
- **Throws**:
659
+ ### Entangld_Message.subscribe(tree, uuid) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
660
+ Construct subscribe message
690
661
 
691
- - <code>TypeError</code> if path is not a string.
662
+ **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
663
+ **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - the `subscribe` message
692
664
 
665
+ | Param | Type | Description |
666
+ | --- | --- | --- |
667
+ | tree | <code>string</code> | the path (relative to the downstream datastore) |
668
+ | uuid | <code>uuidv4</code> | the subscription uuid |
693
669
 
694
- | Param | Type | Default | Description |
695
- | --- | --- | --- | --- |
696
- | path | <code>string</code> | | the path to set (like "system.fan.voltage"). |
697
- | data | <code>object</code> | | the object or function you want to store at path. |
698
- | [operation_type] | <code>string</code> | <code>&quot;\&quot;set\&quot;&quot;</code> | whether to set or push the new data (push only works if the data item exists and is an array). |
699
- | [params] | <code>object</code> | | additional parameters. |
670
+ <a name="Entangld_Message.event"></a>
700
671
 
701
- <a name="Entangld+get"></a>
672
+ ### Entangld_Message.event(path, value, uuid) ⇒ [<code>Entangld\_Message</code>](#Entangld_Message)
673
+ Create an `event` message to return data to subscribe callbacks
702
674
 
703
- ### entangld.get(path, [params]) ⇒ <code>Promise</code>
704
- Get an object from the store.
675
+ **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
676
+ **Returns**: [<code>Entangld\_Message</code>](#Entangld_Message) - the `event` message
705
677
 
706
- Note: using max_depth, especially large max_depth, involves a lot of
707
- recursion and may be expensive.
678
+ | Param | Type | Description |
679
+ | --- | --- | --- |
680
+ | path | <code>string</code> | the path (relative to the downstream store) |
681
+ | value | <code>\*</code> | the updated datastore value at the path |
682
+ | uuid | <code>uuidv4</code> | the uuid of the subscribe being triggered |
708
683
 
709
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
710
- **Returns**: <code>Promise</code> - promise resolving to the object at that path.
711
- **Throws**:
684
+ <a name="Entangld_Message.unsubscribe"></a>
712
685
 
713
- - <code>TypeError</code> if path is not a string.
686
+ ### Entangld_Message.unsubscribe(uuid)
687
+ Create an unsubscribe message for a subscription uuid
714
688
 
689
+ **Kind**: static method of [<code>Entangld\_Message</code>](#Entangld_Message)
715
690
 
716
691
  | Param | Type | Description |
717
692
  | --- | --- | --- |
718
- | path | <code>string</code> | the path to query (like "system.voltage"). |
719
- | [params] | <code>object</code> | the parameters to be passed to the remote function (RPC) or the maximum depth of the returned object (normal mode). |
693
+ | uuid | <code>String</code> | the subscription uuid |
720
694
 
721
- <a name="Entangld+subscribe"></a>
695
+ <a name="Subscription"></a>
722
696
 
723
- ### entangld.subscribe(path, func, [every]) ⇒ <code>Uuid</code>
724
- Subscribe to change events for a path
697
+ ## Subscription
698
+ A datastore subscription object
725
699
 
726
- If objects at or below this path change, you will get a callback
700
+ **Kind**: global class
727
701
 
728
- Subscriptions to keys within attach()ed stores are remote subscriptions.
729
- If several stores are attached in some kind of arrangement, a given key
730
- may actually traverse multiple stores! Since each store only knows its
731
- immediate neighbors - and has no introspection into those neighbors - each
732
- store is only able to keeps track of the neighbor on each side with
733
- respect to a particular path and has no knowledge of the eventual
734
- endpoints. This means that subscribing across several datstores is accomplished
735
- by daisy-chaining 2-way subscriptions across each datastore interface.
702
+ * [Subscription](#Subscription)
703
+ * [new Subscription(obj)](#new_Subscription_new)
704
+ * [.is_pass_through](#Subscription+is_pass_through) ⇒ <code>Boolean</code>
705
+ * [.is_terminal](#Subscription+is_terminal) ⇒ <code>Boolean</code>
706
+ * [.is_head](#Subscription+is_head) ⇒ <code>Boolean</code>
707
+ * [.has_downstream](#Subscription+has_downstream) ⇒ <code>Boolean</code>
708
+ * [.has_upstream](#Subscription+has_upstream) ⇒ <code>Boolean</code>
709
+ * [.call()](#Subscription+call)
710
+ * [.matches_subscription(sub)](#Subscription+matches_subscription) ⇒ <code>Boolean</code>
711
+ * [.matches_event_message(msg)](#Subscription+matches_event_message) ⇒ <code>Boolean</code>
712
+ * [.matches_unsubscribe_message(msg)](#Subscription+matches_unsubscribe_message) ⇒ <code>Boolean</code>
713
+ * [.matches_path(path)](#Subscription+matches_path) ⇒ <code>Boolean</code>
714
+ * [.matches_uuid(uuid)](#Subscription+matches_uuid) ⇒ <code>Boolean</code>
715
+ * [.is_beneath(path)](#Subscription+is_beneath) ⇒ <code>Boolean</code>
716
+ * [.is_above(path)](#Subscription+is_above) ⇒ <code>Boolean</code>
717
+ * [.static_copy()](#Subscription+static_copy) ⇒ [<code>Subscription</code>](#Subscription)
736
718
 
737
- For example, let's suppose capital letters represent Entangld stores and
738
- lowercase letters are actual objects. Then the path "A.B.c.d.E.F.g.h"
739
- will represent a subscription that traverses four Entangld stores.
740
- From the point of view of a store in the middle - say, E - the "upstream"
741
- is B and the "downstream" is F.
719
+ <a name="new_Subscription_new"></a>
742
720
 
743
- Each store involved keeps track of any subscriptions with which it is
744
- involved. It tracks the upstream and downstream, and the uuid of the
745
- subscription. The uuid is the same across all stores for a given
746
- subscription. For a particular store, the upstream is null if it is the
747
- original link in the chain (called the `head`), and the downstream is
748
- null if this store owns the endpoint value (called the `tail`). Any
749
- subscription which is not the head of a chain is called a `pass through`
750
- subscription, because it exist only to pass `event` messages back up the
751
- chain to the head (where the user-provided callback function exists).
752
- subscriptions can be checked to see if they are `pass through` type via
753
- the getter `sub.is_pass_through`.
721
+ ### new Subscription(obj)
722
+ Constructor
754
723
 
755
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
756
- **Returns**: <code>Uuid</code> - - the uuid of the subscription
757
- **Throws**:
724
+ **Returns**: [<code>Subscription</code>](#Subscription) - - the subscription object
758
725
 
759
- - <code>TypeError</code> if path is not a string.
726
+ | Param | Type | Description |
727
+ | --- | --- | --- |
728
+ | obj | <code>Object</code> | the configuration object |
729
+ | obj.path | <code>string</code> | the datastore path (relative to this datastore) of the subscription |
730
+ | obj.uuid | <code>uuidv4</code> | the uuid of the subscription chain |
731
+ | obj.callback | <code>function</code> | the callback function, with signature (path, value), where path is relative to this datastore |
732
+ | obj.downstream | [<code>Entangld</code>](#Entangld) \| <code>null</code> | the downstream datastore (if any) associated with this subscription |
733
+ | obj.upstream | [<code>Entangld</code>](#Entangld) \| <code>null</code> | the upstream datastore (if any) associated with this subscription |
734
+ | obj.every | <code>number</code> \| <code>null</code> | how many `set` messages to wait before calling callback |
760
735
 
736
+ <a name="Subscription+is_pass_through"></a>
761
737
 
762
- | Param | Type | Default | Description |
763
- | --- | --- | --- | --- |
764
- | path | <code>string</code> | | the path to watch. |
765
- | func | <code>function</code> | | the callback - will be of the form (path, value). |
766
- | [every] | <code>number</code> \| <code>null</code> | <code></code> | the number of `set` messages to wait before calling callback |
738
+ ### subscription.is\_pass\_through ⇒ <code>Boolean</code>
739
+ Check if subscription is a `pass through` type
767
740
 
768
- <a name="Entangld+subscribed_to"></a>
741
+ Pass throughs are as the links in a chain of subscriptions to allows
742
+ subscriptions to remote datastores. One store acts as the `head`, where
743
+ the callback function is registered, an all others are `path through` datastores
744
+ which simply pass event messages back up to the head subscription.
769
745
 
770
- ### entangld.subscribed\_to(subscription) ⇒ <code>Boolean</code>
771
- Check for subscription
746
+ **Kind**: instance property of [<code>Subscription</code>](#Subscription)
747
+ <a name="Subscription+is_terminal"></a>
772
748
 
773
- Are we subscribed to a particular remote path?
749
+ ### subscription.is\_terminal ⇒ <code>Boolean</code>
750
+ Check if this subscription will be directly given data by a datastore
774
751
 
775
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
776
- **Returns**: <code>Boolean</code> - true if we are subscribed.
752
+ **Kind**: instance property of [<code>Subscription</code>](#Subscription)
753
+ <a name="Subscription+is_head"></a>
754
+
755
+ ### subscription.is\_head ⇒ <code>Boolean</code>
756
+ Check if this subscription will apply a user-supplied callback to data
757
+
758
+ **Kind**: instance property of [<code>Subscription</code>](#Subscription)
759
+ <a name="Subscription+has_downstream"></a>
760
+
761
+ ### subscription.has\_downstream ⇒ <code>Boolean</code>
762
+ Check if subscription has any downstream subscriptions
763
+
764
+ It the subscription refers to a remote datastore (the downstream), this
765
+ getter will return a true. Note that !this.has_downstream will check if
766
+ the subscription is the `tail` subscription object in a subscription chain.
767
+
768
+ **Kind**: instance property of [<code>Subscription</code>](#Subscription)
769
+ <a name="Subscription+has_upstream"></a>
770
+
771
+ ### subscription.has\_upstream ⇒ <code>Boolean</code>
772
+ Check if subscription has any upstream subscriptions
773
+
774
+ It the subscription passes data back to a remote datastore (the upstream), this
775
+ getter will return a true.
776
+
777
+ **Kind**: instance property of [<code>Subscription</code>](#Subscription)
778
+ <a name="Subscription+call"></a>
779
+
780
+ ### subscription.call()
781
+ Apply this callback function
782
+
783
+ Note, this method also tracks the number of times that a callback
784
+ function is called (if this subscription is terminal), so that if
785
+ the subscriptions are throttled by specifying an `this.every`,
786
+ this method will only call the callback function every `this.every`
787
+ times it receives a `set` message. If this subscription is not
788
+ terminal, then the callback function is called every time.
789
+
790
+ This method also is safed when a callback function is not give (i.e.
791
+ by the `this.static_copy()` method).
792
+
793
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
794
+ <a name="Subscription+matches_subscription"></a>
795
+
796
+ ### subscription.matches\_subscription(sub) ⇒ <code>Boolean</code>
797
+ Check if a different `Subscription` object matches this subscription
798
+
799
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
800
+ **Returns**: <code>Boolean</code> - - True if the subscriptions match
777
801
 
778
802
  | Param | Type | Description |
779
803
  | --- | --- | --- |
780
- | subscription | <code>String</code> | the subscription to check for. |
804
+ | sub | [<code>Subscription</code>](#Subscription) | a different subscription |
781
805
 
782
- <a name="Entangld+unsubscribe"></a>
806
+ <a name="Subscription+matches_event_message"></a>
783
807
 
784
- ### entangld.unsubscribe(path_or_uuid) ⇒ <code>number</code>
785
- Unubscribe to change events for a given path or uuid.
808
+ ### subscription.matches\_event\_message(msg) ⇒ <code>Boolean</code>
809
+ Check if an `event` message matches this subscription
786
810
 
787
- Caution - if a path is provided, _all_ events belonging to you with that
788
- path will be deleted, so if you have multiple subscriptions on a single path,
789
- and only want one of them to be removed, you must provide the uuid instead.
811
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
812
+ **Returns**: <code>Boolean</code> - - True if the message is associated with the subscription
790
813
 
791
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
792
- **Returns**: <code>number</code> - count of subscriptions removed.
793
- **Throws**:
814
+ | Param | Type | Description |
815
+ | --- | --- | --- |
816
+ | msg | [<code>Entangld\_Message</code>](#Entangld_Message) | a received message from a downstream datastore |
794
817
 
795
- - [<code>EntangldError</code>](#EntangldError) if no subscriptions were found.
818
+ <a name="Subscription+matches_unsubscribe_message"></a>
796
819
 
820
+ ### subscription.matches\_unsubscribe\_message(msg) ⇒ <code>Boolean</code>
821
+ Check if an `unsubscribe` message matches this subscription
822
+
823
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
824
+ **Returns**: <code>Boolean</code> - - True if the message is associated with the subscription
797
825
 
798
826
  | Param | Type | Description |
799
827
  | --- | --- | --- |
800
- | path_or_uuid | <code>String</code> \| <code>Uuid</code> | the path (or uuid) to unwatch. |
828
+ | msg | [<code>Entangld\_Message</code>](#Entangld_Message) | a received message from a downstream datastore |
801
829
 
802
- <a name="Entangld+unsubscribe_tree"></a>
830
+ <a name="Subscription+matches_path"></a>
803
831
 
804
- ### entangld.unsubscribe\_tree(path)
805
- Unsubscribe tree.
832
+ ### subscription.matches\_path(path) ⇒ <code>Boolean</code>
833
+ Check if a provided path matches this path
806
834
 
807
- Remove any subscriptions that are beneath a path.
835
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
836
+ **Returns**: <code>Boolean</code> - - true if the path matches
808
837
 
809
- **Kind**: instance method of [<code>Entangld</code>](#Entangld)
810
- **Throws**:
838
+ | Param | Type | Description |
839
+ | --- | --- | --- |
840
+ | path | <code>String</code> | a path string to check against |
811
841
 
812
- - [<code>EntangldError</code>](#EntangldError) error if there are stores we cannot detach
813
- (i.e. they belong to someone else / upstream != null)
842
+ <a name="Subscription+matches_uuid"></a>
814
843
 
844
+ ### subscription.matches\_uuid(uuid) ⇒ <code>Boolean</code>
845
+ Check if a provided uuid matches this uuid
846
+
847
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
848
+ **Returns**: <code>Boolean</code> - - true if the path matches
815
849
 
816
850
  | Param | Type | Description |
817
851
  | --- | --- | --- |
818
- | path | <code>string</code> | the tree to unwatch. |
852
+ | uuid | <code>uuidv4</code> | a uuid string to check against |
853
+
854
+ <a name="Subscription+is_beneath"></a>
855
+
856
+ ### subscription.is\_beneath(path) ⇒ <code>Boolean</code>
857
+ Check if subscription path is beneath a provided path
858
+
859
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
860
+ **Returns**: <code>Boolean</code> - - true if the subscription is beneath the path
861
+
862
+ | Param | Type | Description |
863
+ | --- | --- | --- |
864
+ | path | <code>String</code> | a path string to check against |
865
+
866
+ <a name="Subscription+is_above"></a>
819
867
 
868
+ ### subscription.is\_above(path) ⇒ <code>Boolean</code>
869
+ Check if subscription path is above a provided path
870
+
871
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
872
+ **Returns**: <code>Boolean</code> - - true if the subscription is beneath the path
873
+
874
+ | Param | Type | Description |
875
+ | --- | --- | --- |
876
+ | path | <code>String</code> | a path string to check against |
877
+
878
+ <a name="Subscription+static_copy"></a>
879
+
880
+ ### subscription.static\_copy() ⇒ [<code>Subscription</code>](#Subscription)
881
+ Get a copy of this subscription without external references
882
+
883
+ This creates a copy, except the upstream/downstream references
884
+ are set to true (if they exist) or null (if they don't. Addtionally,
885
+ the callback function is excluded.
886
+
887
+ **Kind**: instance method of [<code>Subscription</code>](#Subscription)
888
+ **Returns**: [<code>Subscription</code>](#Subscription) - a copy of this subscription object
820
889
 
821
890
  ## TODO
822
891
  - Make sure incoming values request store doesn't build up