New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-native-meteor

Package Overview
Dependencies
Maintainers
1
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-native-meteor - npm Package Compare versions

Comparing version 1.0.0-beta2 to 1.0.0-beta20

docs/FSCollection.md

21

docs/Install.md

@@ -0,6 +1,16 @@

# Android
Add this to your AndroidManifest.xml file to autoreconnect fastly to DDP server if your device reconnects to network
```xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
```
# Installing decorators
## With RN >= 0.20.0 (Babel 6)
## With RN >= 0.16.0 (Babel 6)
- `npm i --save-dev babel-plugin-transform-decorators-legacy babel-preset-react-native` in your projet
- `npm i --save-dev babel-plugin-transform-decorators-legacy babel-preset-react-native` in your project
- Create a .babelrc file at the root of your project :

@@ -15,10 +25,5 @@

## With RN >= 0.16.0 && <= 0.19.0 (Babel 6)
Looking for your help. The RN 0.20.0 solution might be working, please let me know ;)
## With RN <0.16.0 (Babel 5)
Use a .babelrc file at the root of your projet that contains :
Use a .babelrc file at the root of your project that contains :

@@ -25,0 +30,0 @@ ```json

{
"name": "react-native-meteor",
"version": "1.0.0-beta2",
"description": "DDP React-native Client",
"version": "1.0.0-beta20",
"description": "Full Meteor Client for React Native",
"main": "src/Meteor.js",

@@ -29,8 +29,9 @@ "scripts": {

"dependencies": {
"ddp.js": "1.1.0",
"crypto-js": "^3.1.6",
"ejson": "^2.1.2",
"minimongo-cache": "0.0.48",
"react-mixin": "^3.0.3",
"trackr": "^2.0.2"
"trackr": "^2.0.2",
"wolfy87-eventemitter": "^4.3.0"
}
}

@@ -15,3 +15,3 @@ [![GitHub version](https://badge.fury.io/gh/inProgress-team%2Freact-native-meteor.svg)](https://badge.fury.io/gh/inProgress-team%2Freact-native-meteor)

Meteor-like methods for React Native. **Currently in v1.0.0-beta1** ! For old docs, see [v0.6.2 documentation](https://github.com/inProgress-team/react-native-meteor/tree/0.6.2) (classic ddp interface).
Meteor-like methods for React Native. **Currently in v1.0.0-beta20** ! For old docs, see [v0.6.2 documentation](https://github.com/inProgress-team/react-native-meteor/tree/0.6.2) (classic ddp interface).

@@ -27,3 +27,3 @@ ## What is it for ?

npm i --save react-native-meteor
npm i --save react-native-meteor@latest

@@ -37,3 +37,3 @@ [!! See detailed installation guide](https://github.com/inProgress-team/react-native-meteor/blob/master/docs/Install.md)

import { View, Text, Component } from 'react-native';
import Meteor, { connectMeteor } from 'react-native-meteor';
import Meteor, { connectMeteor, MeteorListView } from 'react-native-meteor';

@@ -60,18 +60,26 @@ /*

Meteor.subscribe('todos');
Meteor.subscribe('settings');
}
getMeteorData() {
return {
todos: Meteor.collection('todos').find()
settings: Meteor.collection('settings').findOne()
};
}
renderRow(todo) {
return (
<Text>{todo.title}</Text>
);
}
render() {
const { todos } = this.data;
const { settings } = this.data;
{todos.map(todo=>{
return (
<View key={todo._id}>
<Text>{todo.title}</Text>
</View>
)
})}
<View>
<Text>{settings.title}</Text>
<MeteorListView
collection="todos"
selector={{done: true}}
options={{sort: {createdAt: -1}}}
renderRow={this.renderRow}
/>
</View>

@@ -82,4 +90,5 @@ }

# MeteorMixin
# connectMeteor
## startMeteorSubscriptions

@@ -89,5 +98,4 @@

#### [Meteor.subscribe](http://docs.meteor.com/#/full/meteor_subscribe)
* [Meteor.subscribe](http://docs.meteor.com/#/full/meteor_subscribe)
## getMeteorData

@@ -100,3 +108,2 @@

* [.findOne(selector, options)](http://docs.meteor.com/#/full/findone)
* [.findOne(id)](http://docs.meteor.com/#/full/findone)
* [Meteor.user()](http://docs.meteor.com/#/full/meteor_user)

@@ -107,6 +114,50 @@ * [Meteor.userId()](http://docs.meteor.com/#/full/meteor_userid)

# Additionals collection methods
* Meteor.collection(collectionName)
* [.insert(doc, callback)](http://docs.meteor.com/#/full/insert)
* [.update(id, modifier, [options], [callback])](http://docs.meteor.com/#/full/update)
* [.remove(id, callback(err, countRemoved))](http://docs.meteor.com/#/full/remove)
* Meteor.FSCollection(collectionName) : Helper for [Meteor-CollectionFS](https://github.com/CollectionFS/Meteor-CollectionFS). Full documentation [here](https://github.com/inProgress-team/react-native-meteor/blob/master/docs/FSCollection.md)
# MeteorListView Component
Same as [ListView](https://facebook.github.io/react-native/docs/listview.html) Component but does not need dataSource and accepts three arguments :
- `collection` **string** *required*
- `selector` [**string** / **object**]
- `options` **object**
### Example usage
```javascript
<MeteorListView
collection="todos"
selector={{done: true}}
options={{sort: {createdAt: -1}}}
renderRow={this.renderItem}
/>
```
# MeteorComplexListView Component
Same as [ListView](https://facebook.github.io/react-native/docs/listview.html) Component but does not need dataSource and accepts one argument. You may need it if you make complex requests combining multiples collections.
- `elements` **function** *required* : a reactive function which returns an array of elements.
### Example usage
```javascript
<MeteorComplexListView
elements={()=>{return Meteor.collection('todos').find()}}
renderRow={this.renderItem}
/>
```
# API
## Meteor.connect(endpoint)
## Meteor DDP connection
#### Meteor.connect(endpoint, options)
Connect to a DDP server. You only have to do this once in your app.

@@ -117,3 +168,11 @@

- `url` **string** *required*
- `options` **object** Available options are :
- autoConnect **boolean** [true] whether to establish the connection to the server upon instantiation. When false, one can manually establish the connection with the Meteor.ddp.connect method.
- autoReconnect **boolean** [true] whether to try to reconnect to the server when the socket connection closes, unless the closing was initiated by a call to the disconnect method.
- reconnectInterval **number** [10000] the interval in ms between reconnection attempts.
#### Meteor.disconnect()
Disconnect from the DDP server.
## Meteor methods

@@ -124,1 +183,24 @@

* [Meteor.logout](http://docs.meteor.com/#/full/meteor_logout)
* [Meteor.logoutOtherClients](http://docs.meteor.com/#/full/meteor_logoutotherclients)
## Meteor.Accounts
* [Accounts.createUser](http://docs.meteor.com/#/full/accounts_createuser)
* [Accounts.changePassword](http://docs.meteor.com/#/full/accounts_forgotpassword)
* [Accounts.forgotPassword](http://docs.meteor.com/#/full/accounts_changepassword)
## Meteor.ddp
Once connected to the ddp server, you can access every method available in [ddp.js](https://github.com/mondora/ddp.js/).
* Meteor.ddp.on('connected')
* Meteor.ddp.on('added')
* Meteor.ddp.on('changed')
* ...
## react-native-router-flux
* [Github repository](https://github.com/inProgress-team/react-native-meteor-router-flux)
* npm i --save react-native-meteor-router-flux@latest
* [Custom scene renderer](https://github.com/aksonov/react-native-router-flux#switch-new-feature) which allows to select tab scene to show depending from app state. It could be useful for authentication, restricted scenes, etc.
Pull Requests are welcome ! :)

@@ -0,10 +1,22 @@

import React from 'react-native';
import minimongo from 'minimongo-cache';
process.nextTick = setImmediate;
const db = new minimongo();
db.debug = false;
db.batchedUpdates = React.addons.batchedUpdates;
export default {
_endpoint: null,
_options: null,
ddp: null,
subscriptions: {},
db: new minimongo(),
db: db,
calls: [],
hasBeenConnected: false,
getUrl() {
return this._endpoint.substring(0, this._endpoint.indexOf('/websocket'));
},
waitDdpReady(cb) {

@@ -20,14 +32,31 @@ if(this.ddp) {

_cbsLoggingIn: [],
_subscribeLoggingIn(cb) {
this._cbsLoggingIn.push(cb);
_cbs: [],
onChange(cb) {
this.db.on('change', cb);
this.ddp.on('connected', cb);
this.ddp.on('disconnected', cb);
this.on('loggingIn', cb);
},
_unsubscribeLoggingIn(cb) {
this._cbsLoggingIn.splice(this._cbsLoggingIn.indexOf(cb));
offChange(cb) {
this.db.off('change', cb);
this.ddp.off('connected', cb);
this.ddp.off('disconnected', cb);
this.off('loggingIn', cb);
},
on(eventName, cb) {
this._cbs.push({
eventName: eventName,
callback: cb
});
},
off(eventName, cb) {
this._cbs.splice(this._cbs.findIndex(_cb=>_cb.callback == cb && _cb.eventName == eventName), 1);
},
_notifyLoggingIn() {
for(var i in this._cbsLoggingIn) {
this._cbsLoggingIn[i]();
}
this._cbs.map(cb=>{
if(cb.eventName=='loggingIn' && typeof cb.callback=='function') {
cb.callback();
}
});
}
}

@@ -0,28 +1,34 @@

import { NetInfo } from 'react-native';
import reactMixin from 'react-mixin';
import Trackr from 'trackr';
import DDP from 'ddp.js';
import EJSON from 'ejson';
import DDP from '../lib/ddp.js';
import Random from '../lib/Random';
import Data from './Data';
import Mixin from './Mixin';
import User from './User';
import collection from './Collection';
import FSCollection from './FSCollection';
import call from './Call';
import Mixin from './components/Mixin';
import ListView from './components/ListView';
import MeteorComplexListView from './components/ComplexListView';
import User from './user/User';
import Accounts from './user/Accounts';
module.exports = {
Accounts: Accounts,
MeteorListView: ListView,
MeteorComplexListView: MeteorComplexListView,
collection: collection,
FSCollection: FSCollection,
getData() {
return Data
},
connectMeteor(reactClass) {
return reactMixin.onClass(reactClass, Mixin);
},
collection(name) {
return {
find(selector, options) {
if(!Data.db || !Data.db[name]) return [];
return Data.db[name].find(selector, options)
},
findOne(selector, options) {
if(!Data.db || !Data.db[name]) return null;
if(typeof selector == 'string') return this.findOne({_id: selector}, options);
return Data.db[name] && Data.db[name].findOne(selector, options)
}
};
},
...User,

@@ -38,26 +44,64 @@ status() {

},
call(eventName) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length && typeof args[args.length - 1] === "function") {
var callback = args.pop();
call: call,
disconnect() {
if(Data.ddp) {
Data.ddp.disconnect();
}
},
_subscriptionsRestart() {
for(var i in Data.subscriptions) {
const sub = Data.subscriptions[i];
Data.ddp.unsub(sub.subIdRemember);
sub.subIdRemember = Data.ddp.sub(sub.name, sub.params);
}
const id = Data.ddp.method(eventName, args);
Data.calls.push({
id: id,
callback: callback
});
},
connect(endpoint) {
Data.ddp = new DDP({
waitDdpConnected(cb) {
if(Data.ddp && Data.ddp.status == 'connected') {
cb();
} else if(Data.ddp) {
Data.ddp.once('connected', cb);
} else {
setTimeout(()=>{ this.waitDdpConnected(cb) }, 500);
}
},
connect(endpoint, options) {
if(!endpoint) endpoint = Data._endpoint;
if(!options) options = Data._options;
Data._endpoint = endpoint;
Data._options = options;
this.ddp = Data.ddp = new DDP({
endpoint: endpoint,
SocketConstructor: WebSocket
SocketConstructor: WebSocket,
...options
});
NetInfo.isConnected.addEventListener('change', isConnected=>{
if(isConnected) {
Data.ddp.connect();
}
});
Data.ddp.on("connected", ()=>{
console.info("connected");
console.info("Connected to DDP server.");
this._loadInitialUser();
if(Data.hasBeenConnected) {
this._subscriptionsRestart();
} else {
Data.hasBeenConnected = true;
}
});
Data.ddp.on("disconnected", ()=>{
console.info("Disconnected from DDP server.");
});
Data.ddp.on("added", message => {

@@ -71,4 +115,8 @@ if(!Data.db[message.collection]) {

Data.ddp.on("ready", message => {
console.info('READY', message.subs);
//console.log('READY', Data.db.todos && Data.db.todos.find().length);
/*
for(var i in Data.subscriptions) {
const sub = Data.subscriptions[i];
//console.log(sub.name, EJSON.clone(sub.params), sub.subIdRemember);
}
*/
});

@@ -93,62 +141,120 @@

const sub = Data.subscriptions[i];
if(sub.id == message.id) {
console.log("No sub for", sub.name);
if(sub.subIdRemember == message.id) {
console.warn("No subscription existing for", sub.name);
}
}
});
},
subscribe(name) {
const params = Array.prototype.slice.call(arguments, 1);
var params = Array.prototype.slice.call(arguments, 1);
var callbacks = {};
if (params.length) {
var lastParam = params[params.length - 1];
if (typeof lastParam == 'function') {
callbacks.onReady = params.pop();
} else if (lastParam && (typeof lastParam.onReady == 'function' || typeof lastParam.onError == 'function' || typeof lastParam.onStop == 'function')) {
callbacks = params.pop();
}
}
const stringKey = name+JSON.stringify(params);
// Is there an existing sub with the same name and param, run in an
// invalidated Computation? This will happen if we are rerunning an
// existing computation.
//
// For example, consider a rerun of:
//
// Tracker.autorun(function () {
// Meteor.subscribe("foo", Session.get("foo"));
// Meteor.subscribe("bar", Session.get("bar"));
// });
//
// If "foo" has changed but "bar" has not, we will match the "bar"
// subcribe to an existing inactive subscription in order to not
// unsub and resub the subscription unnecessarily.
//
// We only look for one such sub; if there are N apparently-identical subs
// being invalidated, we will require N matching subscribe calls to keep
// them all active.
if (!Data.subscriptions[stringKey]) {
// We're not currently subscribed to this. Go start a subscription.
//console.log("Subscribe to", name, "with params", params);
Data.subscriptions[stringKey] = {
references: 1,
let existing = false;
for(var i in Data.subscriptions) {
const sub = Data.subscriptions[i];
if(sub.inactive && sub.name === name && EJSON.equals(sub.params, params)) existing = sub;
}
let id;
if (existing) {
id = existing.id;
existing.inactive = false;
if (callbacks.onStop) {
existing.stopCallback = callbacks.onStop;
}
} else {
// New sub! Generate an id, save it locally, and send message.
id = Random.id();
const subIdRemember = Data.ddp.sub(name, params);
Data.subscriptions[id] = {
id: id,
subIdRemember: subIdRemember,
name: name,
params: params,
id: Data.ddp.sub(name, params),
stop: function () {
// Wait for all autoruns to finish rerunning before processing the unsubscription
// request. It's possible that stop() was called because an autorun is rerunning,
// so before doing anything drastic, we should wait to see if the autorun
// recreates the subscription when it is rerun.
this.references--;
Trackr.afterFlush(() => {
if (this.references === 0) {
// Nope, either the autorun did not recreate the subscription, or there
// were multiple calls to subscribeToMagazine() in the first place and not all
// of them have been stopped. Go ahead and cancel.
//console.log("Canceling our subscription to", name, "with params", params);
Data.ddp.unsub(Data.subscriptions[stringKey].id);
delete Data.subscriptions[stringKey];
}
});
params: EJSON.clone(params),
inactive: false,
ready: false,
stopCallback: callbacks.onStop,
stop: function() {
Data.ddp.unsub(this.subIdRemember);
delete Data.subscriptions[this.id];
if (callbacks.onStop) {
callbacks.onStop();
}
}
};
} else {
// We already have a subscription to this magazine running. Increment the reference
// count to stop it from going away.
Data.subscriptions[stringKey].references++;
}
// return a handle to the application.
var handle = {
stop: function () {
if(Data.subscriptions[id])
Data.subscriptions[id].stop();
},
ready: function () {
//TODO
},
subscriptionId: id
};
if (Trackr.active) {
Trackr.onInvalidate((c) => {
// subscribeToMagazine was called from inside an autorun, and the autorun is
// about to rerun itself. Tentatively plan to cancel the subscription. If the
// autorun resubscribes to that same magazine when it is rerun, the logic in
// in stop() is smart enough to leave the subscription alone rather than
// canceling and immediately recreating it.
//
// (Tracker.onInvalidate is a shortcut for Tracker.currentComputation.onInvalidate.)
if (Data.subscriptions[stringKey]) {
Data.subscriptions[stringKey].stop();
// We're in a reactive computation, so we'd like to unsubscribe when the
// computation is invalidated... but not if the rerun just re-subscribes
// to the same subscription! When a rerun happens, we use onInvalidate
// as a change to mark the subscription "inactive" so that it can
// be reused from the rerun. If it isn't reused, it's killed from
// an afterFlush.
Trackr.onInvalidate(function (c) {
if(Data.subscriptions[id]) {
Data.subscriptions[id].inactive = true;
}
Trackr.afterFlush(function () {
if (Data.subscriptions[id] && Data.subscriptions[id].inactive) {
handle.stop();
}
});
});
}
return Data.subscriptions[stringKey];
return handle;
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc