├── .meteor
├── .finished-upgraders
├── .gitignore
├── .id
├── cordova-plugins
├── packages
├── platforms
├── release
└── versions
├── README.md
├── client
├── action_creators.jsx
├── lib
│ ├── app.browserify.js
│ └── app.browserify.options.json
├── main.jsx
├── middlewares.jsx
├── reducers.jsx
└── store.jsx
├── leaderboard.css
├── leaderboard.html
├── leaderboard.js
├── packages.json
└── packages
└── npm-container
├── .npm
└── package
│ ├── .gitignore
│ ├── README
│ └── npm-shrinkwrap.json
├── index.js
└── package.js
/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | notices-for-0.9.0
8 | notices-for-0.9.1
9 | 0.9.4-platform-file
10 | notices-for-facebook-graph-api-2
11 | notices-for-0.9.0
12 | notices-for-0.9.1
13 | 0.9.4-platform-file
14 | notices-for-facebook-graph-api-2
15 |
--------------------------------------------------------------------------------
/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | f98bo41q74rpv12upjp8
8 |
--------------------------------------------------------------------------------
/.meteor/cordova-plugins:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | insecure
8 | autopublish
9 | meteor-platform
10 | meteorhacks:npm
11 | npm-container
12 | cosmos:browserify
13 | skinnygeek1010:flux-helpers
14 | reactive-dict
15 | react
16 |
--------------------------------------------------------------------------------
/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 | android
4 | ios
5 |
--------------------------------------------------------------------------------
/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@1.1.0.2
2 |
--------------------------------------------------------------------------------
/.meteor/versions:
--------------------------------------------------------------------------------
1 | autopublish@1.0.3
2 | autoupdate@1.2.1
3 | babel-compiler@5.4.7
4 | babel-runtime@0.1.0
5 | base64@1.0.3
6 | binary-heap@1.0.3
7 | blaze@2.1.2
8 | blaze-tools@1.0.3
9 | boilerplate-generator@1.0.3
10 | callback-hook@1.0.3
11 | check@1.0.5
12 | coffeescript@1.0.6
13 | cosmos:browserify@0.4.0
14 | ddp@1.1.0
15 | deps@1.0.7
16 | ejson@1.0.6
17 | fastclick@1.0.3
18 | geojson-utils@1.0.3
19 | html-tools@1.0.4
20 | htmljs@1.0.4
21 | http@1.1.0
22 | id-map@1.0.3
23 | insecure@1.0.3
24 | jquery@1.11.3_2
25 | json@1.0.3
26 | jsx@0.1.0
27 | launch-screen@1.0.2
28 | livedata@1.0.13
29 | logging@1.0.7
30 | meteor@1.1.6
31 | meteor-platform@1.2.2
32 | meteorhacks:async@1.0.0
33 | meteorhacks:npm@1.3.0
34 | minifiers@1.1.5
35 | minimongo@1.0.8
36 | mobile-status-bar@1.0.3
37 | mongo@1.1.0
38 | npm-container@1.0.0
39 | observe-sequence@1.0.6
40 | ordered-dict@1.0.3
41 | random@1.0.3
42 | react@0.1.1
43 | react-meteor-data@0.1.5
44 | react-runtime@0.13.3_6
45 | react-runtime-dev@0.13.3_5
46 | react-runtime-prod@0.13.3_4
47 | reactive-dict@1.1.0
48 | reactive-var@1.0.5
49 | reload@1.1.3
50 | retry@1.0.3
51 | routepolicy@1.0.5
52 | session@1.1.0
53 | skinnygeek1010:flux-helpers@0.1.0
54 | spacebars@1.0.6
55 | spacebars-compiler@1.0.6
56 | templating@1.1.1
57 | tracker@1.0.7
58 | ui@1.0.6
59 | underscore@1.0.3
60 | url@1.0.4
61 | webapp@1.2.0
62 | webapp-hashing@1.0.3
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Meteor Redux
2 |
3 | Please read the fantastic Redux guide before/after diving into this. At first it may seem very complex
4 | but it turns out to be very simple once you understand the reducer flow.
5 |
6 | **[Redux Guide](http://rackt.github.io/redux/index.html)**
7 |
8 | Basic gist (from Redux guide):
9 |
10 | Meteor apps need to store local app state in an organized way. Using Session works but can lead to
11 | maintainance problems down the road. Redux helps keep things organized and de-coupled.
12 |
13 | ```javascript
14 | // global reactive store is setup on app startup
15 | store = createStoreWithMiddleware(appReducer);
16 |
17 | // store has initial empty values:
18 | // {
19 | // selectedPlayerId: '',
20 | // selectedPlayerName: '',
21 | // foo: 1,
22 | // bar: 2,
23 | // }
24 |
25 |
26 | // view calls action and returns into store dispatcher
27 | //
28 | Template.player.events({
29 | 'click': function () {
30 | store.dispatch( Actions.selectPlayer(this._id) );
31 | }
32 | });
33 |
34 |
35 | // action 'creator' is a normal function that
36 | // just creates an action object and returns it
37 | //
38 | Actions.selectPlayer = function selectPlayer(playerId) {
39 | let player = Players.findOne(playerId);
40 | let playerName = player.name || "N/A";
41 |
42 | return {
43 | type: 'SELECT_PLAYER',
44 | playerId: playerId,
45 | playerName: playerName
46 | };
47 | };
48 |
49 |
50 | // app reducer catches action in switch statement and can mutate the
51 | // data based on action payload metadata. reactState is a reactive-dict
52 | // so we just set the final value and return the dict when done.
53 | //
54 | // if the app was large we could have several reducers that combine the
55 | // state into the final root object. Redux can only have 1 store
56 | //
57 | appReducer = function appReducer(state, action) {
58 | state = state || reacState;
59 | // see action_creators.jsx for action payloads
60 |
61 | switch (action.type) {
62 | case 'SELECT_PLAYER':
63 | // we're setting the reactive dict here
64 | state.set('selectedPlayerId', action.playerId);
65 | state.set('selectedPlayerName', action.playerName);
66 | // then returning the entire dict when done
67 | return state;
68 | case 'INCREMENT_SCORE':
69 | // collections are in Minimongo but you could also keep
70 | // them here if its easier to have all data in one place
71 | // see React repo for example of that
72 | return state;
73 | default:
74 | return state;
75 | }
76 | }
77 |
78 |
79 | // templates can consume this global state with the `store` helper
80 | // but can only mutate it by calling an action
81 | //
82 |
83 | {{#with store 'selectedPlayerName'}}
84 |
87 | {{else}}
88 |
89 |
90 | ```
91 |
92 |
93 |
94 | ### Usage
95 |
96 | - `meteor`
97 | - Open your browser to localhost:3000
98 | - Checkout action/store logs in console after clicking about
99 |
--------------------------------------------------------------------------------
/client/action_creators.jsx:
--------------------------------------------------------------------------------
1 | // action creators are functions that take a param, build up an 'action'
2 | // and return it to the consumer (reducer). This may seem like
3 | // unneeded boilerplate but it's **really** nice to have a file
4 | // with *all* possible ways to mutate the state of the app.
5 |
6 | Actions = {};
7 |
8 | // doesn't return payload because the reactive store state will re-render views
9 | Actions.incrementScore = function incrementScore(playerId) {
10 | Players.update({_id: playerId}, {$inc: {score: 5}});
11 | // TODO call FAILED action on error
12 | return { type: 'INCREMENT_SCORE' };
13 | };
14 |
15 |
16 | Actions.selectPlayer = function selectPlayer(playerId) {
17 | let player = Players.findOne(playerId);
18 | let playerName = player.name || "N/A";
19 |
20 | return {
21 | type: 'SELECT_PLAYER',
22 | playerId: playerId,
23 | playerName: playerName
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/client/lib/app.browserify.js:
--------------------------------------------------------------------------------
1 | Redux = require("redux");
2 | // ReactRedux = require("react-redux");
3 | ReduxDevTools = require("redux-devtools");
4 | ReactReduxDevTools = require("redux-devtools/lib/react");
5 | DevTools = ReactReduxDevTools.DevTools;
6 | DebugPanel = ReactReduxDevTools.DebugPanel;
7 | LogMonitor = ReactReduxDevTools.LogMonitor;
8 |
--------------------------------------------------------------------------------
/client/lib/app.browserify.options.json:
--------------------------------------------------------------------------------
1 | {
2 | "transforms": {
3 | "externalify": {
4 | "global": true,
5 | "external": {
6 | "react": "React.require"
7 | }
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/main.jsx:
--------------------------------------------------------------------------------
1 | Meteor.startup(function() {
2 | React.render(
3 |
4 |
5 |
6 |
7 |
,
8 | document.getElementById('react-root'));
9 | });
10 |
--------------------------------------------------------------------------------
/client/middlewares.jsx:
--------------------------------------------------------------------------------
1 | // middleware allows you to do something in between the dispatch
2 | // and handing it off to the reducer
3 |
4 | // console.log our state changes
5 | logger = store => next => action => {
6 | log('\n[Dispatching]', action);
7 | // essentially call 'dispatch'
8 | let result = next(action);
9 | log('[Store]', store.getState().keys);
10 | return result;
11 | };
12 |
13 | function log() {
14 | if (__debug_redux) {
15 | console.log.apply(console, arguments);
16 | }
17 | }
18 | __debug_redux = true
19 |
--------------------------------------------------------------------------------
/client/reducers.jsx:
--------------------------------------------------------------------------------
1 | // reducers allow you to 'slice' off a part of the single state object which
2 | // lets you think about the domain in a smaller picture. You could use one
3 | // reducer in a small app like this but in large apps this reducer could be
4 | // several hundred lines. See the meteor-flux-leaderboard redux branch for an
5 | // example of this.
6 |
7 | let { incrementScore, selectPlayer, playersChanged } = Actions;
8 |
9 |
10 | // we'll use a reactive dict as the root state object
11 | // so that our views can auto-render on change
12 | var reactiveState = new ReactiveDict('redux-state');
13 |
14 |
15 | appReducer = function appReducer(state, action) {
16 | state = state || reactiveState;
17 | // see action_creators.jsx for action payloads
18 |
19 | switch (action.type) {
20 | case 'SELECT_PLAYER':
21 | state.set('selectedPlayerId', action.playerId);
22 | state.set('selectedPlayerName', action.playerName);
23 | return state;
24 | case 'INCREMENT_SCORE':
25 | return state;
26 | default:
27 | return state;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/client/store.jsx:
--------------------------------------------------------------------------------
1 | const { createStore, combineReducers, applyMiddleware } = Redux;
2 | const { devTools, persistState } = ReduxDevTools;
3 |
4 | // Redux has a single store. to reduce complexity it allows you to combine
5 | // several 'reducer' functions that share this single state object.
6 | // They are combined into one root reducer which is passed to the store,
7 | // however for this app we only have one reducer.
8 |
9 |
10 | // applyMiddleware takes createStore() and returns a new wrapped createStore
11 | // note, this is an optional step to use middleware (we're auto console.log dispatches)
12 | // let createStoreWithMiddleware = applyMiddleware(logger)(createStore);
13 |
14 | const createStoreWithMiddleware =
15 | applyMiddleware(logger)(
16 | devTools()(
17 | persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))(
18 | createStore
19 | )
20 | )
21 | );
22 |
23 | store = createStoreWithMiddleware(appReducer);
24 |
25 |
26 |
27 | // add our own helper for reactive-dicts, you could
28 | // also just call getState
29 | store.getReactiveState = function(key) {
30 | return store.getState().get(key);
31 | };
32 |
33 | // add a global helper for Blaze
34 | UI.registerHelper('store', function(key) {
35 | return store.getState().get(key);
36 | });
37 |
--------------------------------------------------------------------------------
/leaderboard.css:
--------------------------------------------------------------------------------
1 | * {
2 | -moz-box-sizing: border-box;
3 | box-sizing: border-box;
4 | }
5 |
6 | body {
7 | font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
8 | font-size: 16px;
9 | font-weight: normal;
10 | margin: 3em 0;
11 | padding: 0;
12 | }
13 |
14 | .outer {
15 | margin: 0 auto;
16 | max-width: 480px;
17 | }
18 |
19 | .logo {
20 | background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0ZWQgYnkgSWNvTW9vbi5pbyAtLT4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj4KPGcgaWQ9Imljb21vb24taWdub3JlIj4KCTxsaW5lIHN0cm9rZS13aWR0aD0iMSIgeDE9IiIgeTE9IiIgeDI9IiIgeTI9IiIgc3Ryb2tlPSIjNDQ5RkRCIiBvcGFjaXR5PSIiPjwvbGluZT4KPC9nPgoJPHBhdGggZD0iTTI2LjUyIDI0LjcwNWwtNi41Mi0xMS4yOTN2LTcuODc3aDAuNzVjMC42OSAwIDEuMjUtMC41NiAxLjI1LTEuMjVzLTAuNTYtMS4yNS0xLjI1LTEuMjVoLTkuNWMtMC42OSAwLTEuMjUgMC41Ni0xLjI1IDEuMjVzMC41NiAxLjI1IDEuMjUgMS4yNWgwLjc1djcuODc3bC02LjUyIDExLjI5M2MtMS4zNzUgMi4zODEtMC4yNSA0LjMzIDIuNSA0LjMzaDE2LjA0MGMyLjc1IDAgMy44NzUtMS45NDkgMi41LTQuMzN6TTE0LjUgNS41MzVoM2wtMC4wMDIgOC41NDMgMS45OTYgMy40NTdoLTYuOTljMS4xMjMtMS45NDYgMS45OTYtMy40NTkgMS45OTYtMy40NTl2LTguNTQxek0yNC4wMjAgMjYuNTM1aC0xNi4wNDBjLTAuMjU5IDAtMC40NDMtMC4wMzAtMC41NjEtMC4wNjMgMC4wMzEtMC4xMTkgMC4wOTctMC4yOTQgMC4yMjctMC41MTggMCAwIDEuNzA2LTIuOTU3IDMuNDE2LTUuOTJsOS44NzYtMCAzLjQxOCA1LjkyYzAuMTI5IDAuMjI0IDAuMTk1IDAuMzk5IDAuMjI3IDAuNTE4LTAuMTE4IDAuMDMyLTAuMzAzIDAuMDYzLTAuNTYyIDAuMDYzeiIgZmlsbD0iIzAwMDAwMCI+PC9wYXRoPgo8L3N2Zz4K');
21 | background-position: center center;
22 | background-repeat: no-repeat;
23 | background-size: contain;
24 | height: 1.5em;
25 | margin: 0 auto .75em;
26 | width: 1.5em;
27 | }
28 |
29 | .title {
30 | font-size: 1.5em;
31 | font-weight: 600;
32 | letter-spacing: .3em;
33 | margin: 0 0 .25em;
34 | text-align: center;
35 | text-indent: .3em;
36 | text-transform: uppercase;
37 | }
38 |
39 | .subtitle {
40 | color: #999;
41 | font-size: .875em;
42 | margin-bottom: 2em;
43 | text-align: center;
44 | }
45 |
46 | .leaderboard {
47 | border-top: 1px solid #f1f1f1;
48 | counter-reset: ol-counter;
49 | list-style-type: none;
50 | margin: 0 0 1.5em;
51 | padding: 0;
52 | }
53 |
54 | .player {
55 | border-bottom: 1px solid #f1f1f1;
56 | cursor: pointer;
57 | padding: .5em 0;
58 | position: relative;
59 | overflow: hidden;
60 | transition: background 300ms ease-out;
61 | border-left: 4px solid white;
62 | }
63 |
64 | .player:before {
65 | color: #999;
66 | content: counter(ol-counter);
67 | counter-increment: ol-counter;
68 | display: inline-block;
69 | font-weight: 300;
70 | line-height: 3em;
71 | text-align: center;
72 | vertical-align: middle;
73 | width: 3em;
74 | }
75 |
76 | .player .avatar {
77 | display: inline-block;
78 | margin-right: 1em;
79 | vertical-align: middle;
80 | }
81 |
82 | .player .name {
83 | display: inline-block;
84 | font-size: 1.25em;
85 | font-weight: 300;
86 | vertical-align: middle;
87 | }
88 |
89 | .player .score {
90 | color: #333;
91 | display: block;
92 | float: right;
93 | font-size: 1.25em;
94 | font-weight: 600;
95 | line-height: 2.4em;
96 | padding-right: 1.25em;
97 | }
98 |
99 | .player.selected {
100 | background-color: #fefff4;
101 | border-left: #eb5f3a 4px solid;
102 | }
103 |
104 | .player:hover {
105 | background-color: #fefff4;
106 | }
107 |
108 | .details {
109 | overflow: hidden;
110 | }
111 |
112 | .details .name {
113 | display: inline-block;
114 | font-size: 1.5em;
115 | font-weight: 300;
116 | line-height: 2.25rem;
117 | padding-left: 1.25rem;
118 | vertical-align: middle;
119 | }
120 |
121 | .details .inc {
122 | border-radius: 3em;
123 | border: #eb5f3a 1px solid;
124 | background: transparent;
125 | color: #eb5f3a;
126 | cursor: pointer;
127 | float: right;
128 | font-family: 'Source Sans Pro' ,'Helvetica Neue', Helvetica, Arial, sans-serif;
129 | font-size: 1rem;
130 | line-height: 1;
131 | margin: 0;
132 | outline: none;
133 | padding: 10px 30px;
134 | transition: all 200ms ease-in;
135 | }
136 |
137 | .inc:hover {
138 | background: #eb5f3a;
139 | color: #fff;
140 | }
141 |
142 | .inc:active {
143 | box-shadow: rgba(0,0,0,.3) 0 1px 3px 0 inset;
144 | }
145 |
146 | .message {
147 | color: #aaa;
148 | line-height: 2.25rem;
149 | text-align: center;
150 | }
151 |
152 | @media (max-width: 500px) {
153 | .details, .message {
154 | display: block;
155 | position: fixed;
156 | bottom: 0;
157 | background-color: #fafafa;
158 | width: 100%;
159 | padding: 12px 15px;
160 | border-top: 1px solid #ccc;
161 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
162 | }
163 |
164 | .details .name {
165 | font-size: 1.2em;
166 | padding-left: 0;
167 | }
168 |
169 | .details .inc {
170 | padding: 10px 20px;
171 | }
172 |
173 | body {
174 | margin: 2em 0 4em 0;
175 | }
176 |
177 | .player:hover {
178 | background-color: inherit;
179 | }
180 |
181 | .player.selected:hover {
182 | background-color: #fefff4;
183 | }
184 | }
--------------------------------------------------------------------------------
/leaderboard.html:
--------------------------------------------------------------------------------
1 |
2 | Leaderboard
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Leaderboard
11 |
Select a scientist to give them points
12 | {{> leaderboard}}
13 |
14 |
15 |
16 |
17 |
18 |
19 | {{#each players}}
20 | {{> player}}
21 | {{/each}}
22 |
23 |
24 | {{#if store 'selectedPlayerName'}}
25 |
26 |
{{store 'selectedPlayerName'}}
27 |
28 |
29 | {{else}}
30 | Click a player to select
31 | {{/if}}
32 |
33 |
34 |
35 |
36 | {{name}}
37 | {{score}}
38 |
39 |
40 |
--------------------------------------------------------------------------------
/leaderboard.js:
--------------------------------------------------------------------------------
1 | // Set up a collection to contain player information. On the server,
2 | // it is backed by a MongoDB collection named "players".
3 |
4 | Players = new Mongo.Collection("players");
5 |
6 | if (Meteor.isClient) {
7 | // events
8 |
9 | Template.leaderboard.events({
10 | 'click .inc': function () {
11 | var playerId = store.getReactiveState('selectedPlayerId');
12 | store.dispatch( Actions.incrementScore(playerId) );
13 | }
14 | });
15 |
16 | Template.player.events({
17 | 'click': function () {
18 | store.dispatch( Actions.selectPlayer(this._id) );
19 | }
20 | });
21 |
22 | // helpers
23 |
24 | Template.leaderboard.helpers({
25 | players: function () {
26 | return Players.find({}, { sort: { score: -1, name: 1 } });
27 | }
28 | });
29 |
30 | Template.player.helpers({
31 | selected: function () {
32 | var playerId = store.getReactiveState('selectedPlayerId');
33 | return (playerId === this._id) ? 'selected' : '';
34 | }
35 | });
36 | }
37 |
38 | // On server startup, create some players if the database is empty.
39 | if (Meteor.isServer) {
40 | Meteor.startup(function () {
41 | if (Players.find().count() === 0) {
42 | var names = ["Ada Lovelace", "Grace Hopper", "Marie Curie",
43 | "Carl Friedrich Gauss", "Nikola Tesla", "Claude Shannon"];
44 | _.each(names, function (name) {
45 | Players.insert({
46 | name: name,
47 | score: Math.floor(Random.fraction() * 10) * 5
48 | });
49 | });
50 | }
51 | });
52 | }
53 |
--------------------------------------------------------------------------------
/packages.json:
--------------------------------------------------------------------------------
1 | {
2 | "externalify": "0.1.0",
3 | "redux": "1.0.1",
4 | "react-redux": "0.9.0",
5 | "redux-devtools": "1.1.1"
6 | }
7 |
--------------------------------------------------------------------------------
/packages/npm-container/.npm/package/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/packages/npm-container/.npm/package/README:
--------------------------------------------------------------------------------
1 | This directory and the files immediately inside it are automatically generated
2 | when you change this package's NPM dependencies. Commit the files in this
3 | directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
4 | so that others run the same versions of sub-dependencies.
5 |
6 | You should NOT check in the node_modules directory that Meteor automatically
7 | creates; if you are using git, the .gitignore file tells git to ignore it.
8 |
--------------------------------------------------------------------------------
/packages/npm-container/.npm/package/npm-shrinkwrap.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "externalify": {
4 | "version": "0.1.0",
5 | "dependencies": {
6 | "globo": {
7 | "version": "1.0.2",
8 | "dependencies": {
9 | "accessory": {
10 | "version": "1.0.1",
11 | "dependencies": {
12 | "dot-parts": {
13 | "version": "1.0.1"
14 | }
15 | }
16 | },
17 | "is-defined": {
18 | "version": "1.0.0"
19 | },
20 | "ternary": {
21 | "version": "1.0.0"
22 | }
23 | }
24 | },
25 | "map-obj": {
26 | "version": "1.0.1"
27 | },
28 | "replace-require-functions": {
29 | "version": "1.0.0",
30 | "dependencies": {
31 | "detective": {
32 | "version": "4.1.1",
33 | "dependencies": {
34 | "acorn": {
35 | "version": "1.2.2"
36 | },
37 | "defined": {
38 | "version": "1.0.0"
39 | },
40 | "escodegen": {
41 | "version": "1.6.1",
42 | "dependencies": {
43 | "estraverse": {
44 | "version": "1.9.3"
45 | },
46 | "esutils": {
47 | "version": "1.1.6"
48 | },
49 | "esprima": {
50 | "version": "1.2.5"
51 | },
52 | "optionator": {
53 | "version": "0.5.0",
54 | "dependencies": {
55 | "prelude-ls": {
56 | "version": "1.1.2"
57 | },
58 | "deep-is": {
59 | "version": "0.1.3"
60 | },
61 | "wordwrap": {
62 | "version": "0.0.3"
63 | },
64 | "type-check": {
65 | "version": "0.3.1"
66 | },
67 | "levn": {
68 | "version": "0.2.5"
69 | },
70 | "fast-levenshtein": {
71 | "version": "1.0.6"
72 | }
73 | }
74 | },
75 | "source-map": {
76 | "version": "0.1.43",
77 | "dependencies": {
78 | "amdefine": {
79 | "version": "1.0.0"
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 | },
87 | "has-require": {
88 | "version": "1.2.1",
89 | "dependencies": {
90 | "escape-string-regexp": {
91 | "version": "1.0.3"
92 | }
93 | }
94 | },
95 | "patch-text": {
96 | "version": "1.0.2"
97 | },
98 | "xtend": {
99 | "version": "4.0.0"
100 | }
101 | }
102 | },
103 | "through2": {
104 | "version": "0.4.2",
105 | "dependencies": {
106 | "readable-stream": {
107 | "version": "1.0.33",
108 | "dependencies": {
109 | "core-util-is": {
110 | "version": "1.0.1"
111 | },
112 | "isarray": {
113 | "version": "0.0.1"
114 | },
115 | "string_decoder": {
116 | "version": "0.10.31"
117 | },
118 | "inherits": {
119 | "version": "2.0.1"
120 | }
121 | }
122 | },
123 | "xtend": {
124 | "version": "2.1.2",
125 | "dependencies": {
126 | "object-keys": {
127 | "version": "0.4.0"
128 | }
129 | }
130 | }
131 | }
132 | },
133 | "transformify": {
134 | "version": "0.1.2",
135 | "dependencies": {
136 | "readable-stream": {
137 | "version": "1.1.13",
138 | "dependencies": {
139 | "core-util-is": {
140 | "version": "1.0.1"
141 | },
142 | "isarray": {
143 | "version": "0.0.1"
144 | },
145 | "string_decoder": {
146 | "version": "0.10.31"
147 | },
148 | "inherits": {
149 | "version": "2.0.1"
150 | }
151 | }
152 | }
153 | }
154 | }
155 | }
156 | },
157 | "react-redux": {
158 | "version": "0.9.0",
159 | "dependencies": {
160 | "invariant": {
161 | "version": "2.2.1",
162 | "dependencies": {
163 | "loose-envify": {
164 | "version": "1.2.0",
165 | "dependencies": {
166 | "js-tokens": {
167 | "version": "1.0.3"
168 | }
169 | }
170 | }
171 | }
172 | }
173 | }
174 | },
175 | "redux": {
176 | "version": "1.0.1"
177 | },
178 | "redux-devtools": {
179 | "version": "1.1.1",
180 | "dependencies": {
181 | "react-mixin": {
182 | "version": "1.7.0",
183 | "dependencies": {
184 | "object-assign": {
185 | "version": "2.1.1"
186 | },
187 | "smart-mixin": {
188 | "version": "1.2.1"
189 | }
190 | }
191 | }
192 | }
193 | }
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/packages/npm-container/index.js:
--------------------------------------------------------------------------------
1 | Meteor.npmRequire = function(moduleName) {
2 | var module = Npm.require(moduleName);
3 | return module;
4 | };
5 |
6 | Meteor.require = function(moduleName) {
7 | console.warn('Meteor.require is deprecated. Please use Meteor.npmRequire instead!');
8 | return Meteor.npmRequire(moduleName);
9 | };
--------------------------------------------------------------------------------
/packages/npm-container/package.js:
--------------------------------------------------------------------------------
1 | var path = Npm.require('path');
2 | var fs = Npm.require('fs');
3 |
4 | Package.describe({
5 | summary: 'Contains all your npm dependencies',
6 | version: '1.0.0',
7 | name: 'npm-container'
8 | });
9 |
10 | var packagesJsonFile = path.resolve('./packages.json');
11 | try {
12 | var fileContent = fs.readFileSync(packagesJsonFile);
13 | var packages = JSON.parse(fileContent.toString());
14 | Npm.depends(packages);
15 | } catch (ex) {
16 | console.error('ERROR: packages.json parsing error [ ' + ex.message + ' ]');
17 | }
18 |
19 | // Adding the app's packages.json as a used file for this package will get
20 | // Meteor to watch it and reload this package when it changes
21 | Package.onUse(function(api) {
22 | api.add_files(['index.js', '../../packages.json'], 'server');
23 | });
--------------------------------------------------------------------------------